#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
const int MAX = 50005;
vector<int> edges[MAX];
int from[MAX], to[MAX], color[MAX], cost[MAX];
bool cmp(int x, int y)
{
	return (color[x] < color[y]);
}
vector<pair<int, int> > bads;
vector<int> adj[8 * MAX], tmp[8 * MAX];
int n, m, sz;
void init()
{
	for (int i = 0; i < 8 * MAX; i++)
		adj[i].clear();
	for (int i = 0; i < (int)bads.size(); i++)
	{
		int id1 = bads[i].first, id2 = bads[i].second;
		adj[2 * id1].push_back(2 * id2 + 1);
		adj[2 * id2].push_back(2 * id1 + 1);
	}
	sz = m;
	for (int v = 0; v < n; v++)
		if (!edges[v].empty())
		{
			int last = edges[v][0];
			for (int i = 1; i < (int)edges[v].size(); i++)
			{
				int id = edges[v][i];
				adj[2 * last + 1].push_back(2 * id);
				adj[2 * id + 1].push_back(2 * last);
				adj[2 * id + 1].push_back(2 * sz + 1);
				adj[2 * sz].push_back(2 * id);
				adj[2 * last + 1].push_back(2 * sz + 1);
				adj[2 * sz].push_back(2 * last);
				last = sz++;
			}
		}
}
vector<int> tp;
bool mark[8 * MAX];
void dfs(int v)
{
	mark[v] = true;
	for (int i = 0; i < (int)adj[v].size(); i++)
	{
		int u = adj[v][i];
		if (!mark[u])
			dfs(u);
	}
	tp.push_back(v);
}
int cc[8 * MAX];
void sfd(int v, int col)
{
	mark[v] = true;
	cc[v] = col;
	for (int i = 0; i < (int)adj[v].size(); i++)
	{
		int u = adj[v][i];
		if (!mark[u])
			sfd(u, col);
	}
}
vector<int> ans;
bool check(int lim)
{
	init();
	sz *= 2;
	for (int i = 0; i < m; i++)
		if (cost[i] > lim)
			adj[2 * i + 1].push_back(2 * i);
	memset(mark, false, sizeof(mark));
	tp.clear();
	for (int i = 0; i < sz; i++)
		if (!mark[i])
			dfs(i);
	reverse(tp.begin(), tp.end());
	for (int i = 0; i < sz; i++)
		tmp[i].clear();
	for (int v = 0; v < sz; v++)
		for (int i = 0; i < (int)adj[v].size(); i++)
			tmp[adj[v][i]].push_back(v);
	for (int i = 0; i < sz; i++)
		adj[i] = tmp[i];
	int cnt = 0;
	memset(mark, false, sizeof(mark));
	for (int i = 0; i < (int)tp.size(); i++)
		if (!mark[tp[i]])
			sfd(tp[i], cnt++);
	ans.clear();
	for (int i = 0; i < sz / 2; i++)
	{
		if (cc[2 * i] == cc[2 * i + 1])
			return false;
		if (i < m && cc[2 * i] < cc[2 * i + 1])
			ans.push_back(i);
	}
	return true;
}
int main()
{
	ios::sync_with_stdio(false);
	cin >> n >> m;
	vector<int> vals;
	vals.push_back(0);
	for (int i = 0; i < m; i++)
	{
		cin >> from[i] >> to[i] >> color[i] >> cost[i];
		vals.push_back(cost[i]);
		from[i]--;
		to[i]--;
		edges[from[i]].push_back(i);
		edges[to[i]].push_back(i);
	}
	for (int v = 0; v < n; v++)
	{
		sort(edges[v].begin(), edges[v].end(), cmp);
		int cnt = 0;
		for (int i = 0; i < (int)edges[v].size(); i++)
		{
			int j = i + 1;
			while (j < (int)edges[v].size() && color[edges[v][j - 1]] == color[edges[v][j]])
				j++;
			if (j - i > 2)
			{
				cout << "No\n";
				return 0;
			}
			if (j - i == 2)
			{
				cnt++;
				if (cnt == 2)
				{
					cout << "No\n";
					return 0;
				}
				bads.push_back(make_pair(edges[v][i], edges[v][i + 1]));
				i++;
			}
		}
	}
	sort(vals.begin(), vals.end());
	vals.resize(unique(vals.begin(), vals.end()) - vals.begin());
	int l = -1, r = (int)vals.size();
	while (r - l > 1)
	{
		int mid = (l + r) / 2;
		if (check(vals[mid]))
			r = mid;
		else
			l = mid;
	}
	if (r == (int)vals.size())
	{
		cout << "No\n";
		return 0;
	}
	check(vals[r]);
	cout << "Yes\n";
	cout << vals[r] << " " << ans.size() << "\n";
	for (int i = 0; i < (int)ans.size(); i++)
		cout << ans[i] + 1 << " ";
	cout << "\n";
	return 0;
}
