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 <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 ff first
#define ss second
#define pb push_back
#define pf push_front
#define mp make_pair
#define popb pop_back
#define popf pop_front
#define all(v) v.begin(), v.end()
#define fori(i, j, k) for (int i = (j); i < (int)(k); i++)
#define forb(i, j, k) for (int i = (j); i >= (int)k; i--)
#define lchild(ind) 2 * ind + 1
#define rchild(ind) 2 * ind + 2
#define bug(val) cout << "# " << val << endl;
#define bugs(val) cout << '_' << val;
#define bugl(val) cout << "## " << val << endl;

template<typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<int, ll> pil;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef pair<int, pll> pip;
typedef pair<ll, pll> plp;
typedef pair<pll, int> ppi;
typedef pair<pll, ll> ppl;
typedef pair<pll, pll> ppp;
typedef vector<int> vi;
typedef vector<ll> vll;

const int maxn = 5e5 + 1;
const ll inf = 2e18, mod = 1e9 + 7;

struct EDGE
{
	int u, v, c, t, ind;
} edge[maxn];

int n, m, extra, ans[maxn];
vector<pii> clause, fix;
vi graph[maxn], pref, suf, satg[maxn], topol;
map<int, int> cnt;
bool visited[maxn];

bool cmp(EDGE a, EDGE b)
{
	return (a.t < b.t);
}

void setup()
{
	int CNT, clr;
	vi tmp;
	fori (i, 0, n)
	{
		cnt.clear();
		CNT = 0;
		clr = -1;
		for (int j : graph[i])
		{
			cnt[edge[j].c]++;
			if (cnt[edge[j].c] > 2)
			{
				cout << "No" << endl;
				exit(0);
			}
			else if (cnt[edge[j].c] == 2)
			{
				CNT++;
				clr = edge[j].c;
			}
			if (CNT > 1)
			{
				cout << "No" << endl;
				exit(0);
			}
		}
		tmp.clear();
		if (CNT == 1)
		{
			for (int j : graph[i])
				if (edge[j].c == clr)
					tmp.pb(edge[j].ind);
			clause.pb(mp(tmp[0], tmp[1]));
		}
	}
	extra = 2 * m + 1;
	fori (i, 0, n)
	{
		pref.clear();
		suf.clear();
		if (graph[i].empty())
			continue;
		fix.pb(mp(edge[graph[i][0]].ind, extra));
		pref.pb(extra);
		extra += 2;
		fori (j, 1, graph[i].size())
		{
			fix.pb(mp(pref.back(), extra));
			fix.pb(mp(edge[graph[i][j]].ind, extra));
			pref.pb(extra);
			extra += 2;
		}
		fix.pb(mp(edge[graph[i].back()].ind, extra));
		suf.pb(extra);
		extra += 2;
		forb (j, graph[i].size() - 2, 0)
		{
			fix.pb(mp(suf.back(), extra));
			fix.pb(mp(edge[graph[i][j]].ind, extra));
			suf.pb(extra);
			extra += 2;
		}
		reverse(all(suf));
		fori (j, 0, graph[i].size())
		{
			int now = edge[graph[i][j]].ind;
			if (j)
				clause.pb(mp(pref[j - 1] ^ 1, now ^ 1));
			if (j < (int)(graph[i].size() - 1))
				clause.pb(mp(suf[j + 1] ^ 1, now ^ 1));
		}
		/* cerr << '#' << i << endl;
		for (int j : pref)
			cerr << '_' << j;
		cerr << endl;
		for (int j : suf)
			cerr << '_' << j;
		cerr << endl; */
	}
}

void dfs(int u)
{
	visited[u] = true;
	for (int i : satg[u])
		if (!visited[i])
			dfs(i);
	topol.pb(u);
}

bool check(int ind)
{
	fori (i, 0, maxn)
		satg[i].clear();
	vector<pii> tmp;
	fori (i, ind + 1, m)
		tmp.pb(mp(edge[i].ind ^ 1, edge[i].ind ^ 1));
	for (pii i : clause)
	{
		satg[i.ff ^ 1].pb(i.ss);
		satg[i.ss ^ 1].pb(i.ff);
	}
	for (pii i : tmp)
	{
		satg[i.ff ^ 1].pb(i.ss);
		satg[i.ss ^ 1].pb(i.ff);
	}
	for (pii i : fix)
		satg[i.ff].pb(i.ss);
	memset(visited, false, sizeof(visited));
	topol.clear();
	fori (i, 0, extra)
		if (!visited[i])
			dfs(i);
	fill(ans, ans + maxn, -1);
	// cerr << ind << '#';
	// for (int i : topol)
	// 	cerr << i << ' ';
	// cerr << endl;
	for (int i : topol)
		if (ans[i] == -1)
		{
			ans[i] = 1;
			ans[i ^ 1] = 0;
		}
	bool check = true;
	for (pii i : clause)
		check &= (ans[i.ff] || ans[i.ss]);
	for (pii i : tmp)
		check &= (ans[i.ff] || ans[i.ss]);
	return check;
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	cin >> n >> m;
	fori (i, 0, m)
	{
		cin >> edge[i].u >> edge[i].v >> edge[i].c >> edge[i].t;
		edge[i].ind = 2 * i + 1;
		edge[i].u--;
		edge[i].v--;
	}
	sort(edge, edge + m, cmp);
	fori (i, 0, m)
	{
		graph[edge[i].u].pb(i);
		graph[edge[i].v].pb(i);
	}
	setup();
	int l = 0, r = m, mid;
	while (r - l > 1)
	{
		mid = (l + r) / 2;
		if (check(mid))
			r = mid;
		else
			l = mid;
	}
	check(r);
	cout << "Yes" << endl;
	int CNT = 0;
	fori (i, 0, m)
		CNT += (ans[2 * i + 1] == 1);
	cout << edge[r].t << ' ' << CNT << endl;
	fori (i, 0, m)
		if (ans[2 * i + 1] == 1)
			cout << i + 1 << ' ';
	cout << endl;
}
 		   	 	  	   				  	  	  			