#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#define Foreach(i, c) for(__typeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)
#define For(i,a,b) for(int (i)=(a);(i) < (b); ++(i))
#define rof(i,a,b) for(int (i)=(a);(i) > (b); --(i))
#define rep(i, c) for(auto &(i) : (c))
#define x first
#define y second
#define pb push_back
#define PB pop_back()
#define iOS ios_base::sync_with_stdio(false)
#define sqr(a) (((a) * (a)))
#define all(a) a.begin() , a.end()
#define error(x) cerr << #x << " = " << (x) <<endl
#define Error(a,b) cerr<<"( "<<#a<<" , "<<#b<<" ) = ( "<<(a)<<" , "<<(b)<<" )\n";
#define errop(a) cerr<<#a<<" = ( "<<((a).x)<<" , "<<((a).y)<<" )\n";
#define coud(a,b) cout<<fixed << setprecision((b)) << (a)
#define L(x) ((x)<<1)
#define R(x) (((x)<<1)+1)
#define umap unordered_map
#define double long double
typedef long long ll;
typedef pair<int,int>pii;
typedef vector<int> vi;
typedef complex<double> point;
template <typename T> using os =  tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <class T>  inline void smax(T &x,T y){ x = max((x), (y));}
template <class T>  inline void smin(T &x,T y){ x = min((x), (y));}
const int maxn = 5e4 + 10, maxN = 6 * maxn;
int n, m, comp[maxN];
vi adj[maxN], adl[maxN];
bool mark[maxN];
struct edge{
	int v, u, c, t;
}e[maxn];
vi ed[maxn];
inline int neg(int x){
	return x ^ 1;
}
inline void add_edge(int v, int u){
	adj[v].pb(u);
	adl[u].pb(v);
}
inline void add_clause(int v, int u){
	add_edge(neg(v), u);
	add_edge(neg(u), v);
}
int sz[maxN], SZ[maxN];
stack <int> s;
inline void dfs(int v){
	mark[v] = true;
	rep(u, adj[v])	if(!mark[u])
		dfs(u);
	s.push(v);
}
bool flag = true;
inline void dfs(int v, int c){
	comp[v] = c;
	if(comp[v] == comp[neg(v)]){
		flag = false;
		return ;
	}
	rep(u, adl[v])	if(!comp[u]){
		dfs(u, c);
		if(!flag)	return ;
	}
}
int nex;
inline bool check(int T){
	flag = true;
	For(i,0,nex){
		mark[i] = false;
		adj[i].resize(sz[i]);
		adl[i].resize(SZ[i]);
		comp[i] = 0;
	}
	while(!s.empty())	s.pop();
	For(i,0,m)	if(e[i].t > T)
		add_edge(L(i), R(i));
	For(i,0,nex)
		if(!mark[i])
			dfs(i);
	int cnt = 1;
	while(!s.empty()){
		int v = s.top();
		s.pop();
		if(comp[v])	continue;
		dfs(v, cnt ++);
		if(!flag)	return false;
	}
	return flag;
}
vi ts = {0};
int main(){
	scanf("%d %d", &n, &m);
	For(i,0,m){
		scanf("%d %d %d %d", &e[i].v, &e[i].u, &e[i].c, &e[i].t);
		-- e[i].v;
		-- e[i].u;
		ed[e[i].v].pb(i);
		ed[e[i].u].pb(i);
		ts.pb(e[i].t);
	}
	nex = L(m);
	For(i,0,n){
		sort(all(ed[i]), [](const int &x, const int &y){return e[x].c < e[y].c;});
		int cnt = 0;
		int prv;
		if(!ed[i].empty()){
			prv = nex;
			nex += 2;
			add_clause(R(ed[i][0]), prv);
		}
		For(j,1,ed[i].size()){
			int x = ed[i][j-1], y = ed[i][j];
			int cur = nex;
			nex += 2;
			if(e[x].c == e[y].c){
				++ cnt;
				if(cnt >  1){
					puts("No");
					return 0;
				}
				add_clause(L(x), L(y));
			}
			add_clause(R(y), cur);
			add_clause(neg(prv), cur);
			add_clause(neg(prv), R(y));
			prv = cur;
		}
	}
	For(i,0,maxN)
		sz[i] = adj[i].size(),SZ[i] = adl[i].size();
	sort(all(ts));
	ts.resize(unique(all(ts)) - ts.begin());
	int lo = 0, hi = ts.size() - 1;
	while(lo < hi){
		int mid = (lo + hi)/2;
		if(check(ts[mid]))
			hi = mid;
		else
			lo = mid + 1;
	}
	if(lo >= (int)ts.size() or !check(ts[lo])){
		puts("No");
		return 0;
	}
	puts("Yes");
	fill(mark, mark + nex, false);
	int T = ts[lo];
	For(i,0,nex){
		int v = comp[i], u = comp[neg(i)];
		mark[min(v, u)] = false;
		mark[max(v, u)] = true;
	}
	vi ans;
	For(i,0,m)
		if(mark[comp[L(i)]])
			ans.pb(i + 1);
	int K = ans.size();
	printf("%d %d\n", T, K);
	int cnt = 0;
	rep(i, ans){
		printf("%d", i);
		++ cnt;
		if(cnt == K)
			puts("");
		else
			printf(" ");
	}
	return 0;
}