3 5
2 1 608591421 720962564
3 2 608591421 641991574
3 2 718110706 353409763
2 3 482786015 858341723
3 2 825397574 357507279
 2 1
2 1 317425595 636156322
 50000 1
20845 28516 904146168 997637433

Yes
641991574 1
2 
 Yes
0 0

 Yes
0 0


#include <cstdio>
#include <vector>
#include <algorithm>

#define Int register int

using namespace std;

const int MAXN = 5e4, MAXM = 5e4, MAXE = MAXM << 2;
int n, m, Cnte, tmpc[MAXM + 5], Visc[MAXM + 5], Head[MAXN * 2 + 5];
int Indx, Top, SCC, DFN[MAXN * 2 + 5], Low[MAXN * 2 + 5], Col[MAXN * 2 + 5], S[MAXN * 2 + 5];
bool Instack[MAXN * 2 + 5];
vector<int> Lk[MAXN + 5], Near[MAXM + 5], Ans;

struct Edge { int To, nxt; } Graph[MAXE + 5];

struct RealEdge {
	int u, v, c, t, id;
	inline bool operator < ( const RealEdge e ) const { return t < e.t; }
} E[MAXM + 5];

inline int rint () {
	int x = 0; char s = getchar ();
	for ( ; s < '0' || '9' < s; s = getchar () );
	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = ( x << 3 ) + ( x << 1 ) + ( s ^ '0' );
	return x;
}

inline int Min ( const int a, const int b ) { return a < b ? a : b; }

inline void Link ( const int f, const int t ) { Graph[++ Cnte] = { t, Head[f] }, Head[f] = Cnte; }

inline void Tarjan ( const int u ) {
	int v;
	DFN[u] = Low[u] = ++ Indx, Instack[S[++ Top] = u] = true;
	for ( Int i = Head[u]; i; i = Graph[i].nxt ) {
		if ( ! DFN[v = Graph[i].To] ) {
			Tarjan ( v );
			Low[u] = Min ( Low[u], Low[v] );
		} else if ( Instack[v] ) {
			Low[u] = Min ( Low[u], DFN[v] );
		}
	}
	if ( DFN[u] == Low[u] ) {
		++ SCC;
		do {
			Col[v = S[Top --]] = SCC;
			Instack[v] = false;
		} while ( v ^ u );
	}
}

inline bool Check ( const int x ) {
//	printf ( "---check %d---\n", x );
	Cnte = Indx = SCC = 0;
	for ( Int i = 1; i <= m << 1; ++ i ) Head[i] = DFN[i] = Low[i] = Col[i] = 0;
	for ( Int i = 1; i <= m; ++ i ) {
//		printf ( "%d:", i );
		for ( int nid: Near[i] ) {
//			printf ( " %d", nid );
			Link ( i, nid + m ), Link ( nid + m, i );
		}
//		putchar ( '\n' );
	}
	for ( Int i = m; i > x; -- i ) Link ( i + m, i );
	for ( Int i = 1; i <= m << 1; ++ i ) {
		if ( ! DFN[i] ) {
			Tarjan ( i );
		}
	}
	for ( Int i = 1; i <= m; ++ i ) {
		if ( Col[i] == Col[i + m] ) {
			return false;
		}
	}
	return true;
}

inline void Work () {
	n = rint (), m = rint ();
	for ( Int i = 1, u, v, c, t; i <= m; ++ i ) {
		u = rint (), v = rint (), tmpc[i] = c = rint (), t = rint ();
		E[i] = { u, v, c, t, i };
	}
	sort ( tmpc + 1, tmpc + m + 1 ), sort ( E + 1, E + m + 1 );
	int ccnt = unique ( tmpc + 1, tmpc + n + 1 ) - tmpc - 1;
	for ( Int i = 1; i <= m; ++ i ) {
		E[i].c = lower_bound ( tmpc + 1, tmpc + ccnt + 1, E[i].c ) - tmpc;
		Lk[E[i].u].push_back ( i ), Lk[E[i].v].push_back ( i );
	}
	for ( Int i = 1; i <= n; ++ i ) {
		for ( int id: Lk[i] ) {
			if ( ! Visc[E[id].c] ) Visc[E[id].c] = id;
			else if ( ~ Visc[E[id].c] ) Near[id].push_back ( Visc[E[id].c] ), Near[Visc[E[id].c]].push_back ( id ), Visc[E[id].c] = -1;
			else return puts ( "No" ), void ();
		}
		for ( int id: Lk[i] ) Visc[E[id].c] = 0;
	}
	// id: no distructive. id + m: distructive.
	int l = 0, r = m, mid;
	while ( l < r ) {
		mid = l + r >> 1;
		if ( Check ( mid ) ) r = mid;
		else l = mid + 1;
	}
	if ( ! Check ( l ) ) return puts ( "No" ), void ();
	int Cnt = 0;
	for ( Int i = 1; i <= m; ++ i ) {
		if ( Col[i] < Col[i + m] ) {
			++ Cnt;
		}
	}
	for ( Int i = 1; i <= m; ++ i ) {
		if ( Cnt < m >> 1 ? ( Col[i] < Col[i + m] ) : ( Col[i] > Col[i + m] ) ) {
			Ans.push_back ( E[i].id );
		}
	}
	printf ( "Yes\n%d %d\n", E[l].t, ( int ) Ans.size () );
	for ( Int i = 0; i ^ Ans.size (); ++ i ) printf ( "%d%c", Ans[i], i + 1 == ( int ) Ans.size () ? '\n' : ' ' );
}

int main () {
	Work ();
	return 0;
}