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 <cstring>
#include <cstdlib>
#include <cmath>
#include <complex>
#include <string>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <iostream>
#include <map>
#include <set>
using namespace std;
typedef pair<int,int> P;
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vll;
#define pu push
#define pb push_back
#define mp make_pair
#define eps 1e-9
#define INF 1000000100
#define sz(x) ((int)(x).size())
#define fi first
#define sec second
#define SORT(x) sort((x).begin(),(x).end())
#define all(x) (x).begin(),(x).end()
#define rep(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define repn(i,a,n) for(int (i)=(a);(i)<(int)(n);(i)++)
#define EQ(a,b) (abs((a)-(b))<eps)

#define MAX_V 300100
#define MAX_N 50010

int V;
vector<int> G[MAX_V];
vector<int> rG[MAX_V];
vector<int> vs;
bool used[MAX_V];
int cmp[MAX_V];
void clear_graph()
{
	for(int i=0;i<MAX_V;i++)
	{
		G[i].clear();
		rG[i].clear();
	}
	vs.clear();
}
void add_edge(int from,int to)
{
	//printf("f %d t %d\n",from,to);
	G[from].pb(to);
	rG[to].pb(from);
}
void dfs(int v)
{
	used[v]=true;
	for(int i=0;i<G[v].size();i++)
	{
		if(!used[G[v][i]])dfs(G[v][i]);
	}
	vs.pb(v);
}
void rdfs(int v,int k)
{
	used[v]=true;
	cmp[v]=k;
	for(int i=0;i<rG[v].size();i++)
	{
		if(!used[rG[v][i]])rdfs(rG[v][i],k);
	}
}
void scc()
{
	memset(cmp,-1,sizeof(cmp));
	memset(used,false,sizeof(used));
	for(int i=0;i<V;i++)if(!used[i])dfs(i);
	int k=0;
	memset(used,false,sizeof(used));
	for(int i=(int)vs.size()-1;i>=0;i--)
	{
		if(!used[vs[i]])rdfs(vs[i],k++);
	}
}


int n,m;
vector<int> adj[MAX_N];
int col[MAX_N];
int t[MAX_N];
map<int,int> cnt,cnt2;
vector<int> use[MAX_N];
int must[MAX_N];
int ind;
bool make_graph(int limit)
{
	memset(must,-1,sizeof(must));
	for(int i=0;i<n;i++)use[i].clear();
	for(int i=0;i<n;i++)
	{
		int c=0;
		cnt.clear();
		cnt2.clear();
		for(int j=0;j<adj[i].size();j++)
		{
			int id = adj[i][j];
			if(t[id]<=limit)
			{
				cnt[col[id]]++;
				use[i].pb(id);
			}
			else
			{
				cnt2[col[id]]++;
				if(cnt2[col[id]]>1)return false;
			}
		}
		map<int,int>::iterator it;
		for(it=cnt.begin();it!=cnt.end();it++)
		{
			if((it->sec)>2)return false;
			if((it->sec)==2)
			{
				c++;
				must[i]=it->fi;
			}
		}
		if(c>1)return false;
	}
	//0...m-1 m...2*m-1
	ind = 2*m;
	clear_graph();
	for(int i=0;i<n;i++)
	{
		int num = (int)use[i].size();
		int m1=-1,m2=-1;
		// ind...ind+num-1
		// ind+num...ind+2*num-1
		for(int j=0;j<num;j++)
		{
			add_edge(ind+j,use[i][j]+m);
			if(j<num-1)add_edge(ind+j,ind+j+1);
			
			add_edge(ind+num+j,use[i][j]+m);
			if(j>0)add_edge(ind+num+j,ind+num+j-1);
			
			if(j<num-1)add_edge(use[i][j],ind+j+1);
			if(j>0)add_edge(use[i][j],ind+num+j-1);
			
			if(col[use[i][j]]==must[i])
			{
				if(m1==-1)m1=use[i][j];
				else m2=use[i][j];
			}
		}
		if(m1!=-1&&m2!=-1)
		{
			add_edge(m1+m,m2);
			add_edge(m2+m,m1);
		}
		ind += 2*num;
	}
	V = ind;
	return true;
}

vector<int> ans;

bool check(int limit,bool recover)
{
	if(!make_graph(limit))return false;
	scc();
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<use[i].size();i++)
		{
			int id = use[i][j];
			if(cmp[id]==cmp[id+m])return false;
			if(recover&&cmp[id]>cmp[id+m])ans.pb(id+1);
		}
	}
	return true;
}

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=0;i<m;i++)
	{
		int u,v;
		scanf("%d %d %d %d",&u,&v,&col[i],&t[i]);
		u--;v--;
		adj[u].pb(i);
		adj[v].pb(i);
	}

	//check(2,false);
	int l = -1,r = INF;
	while(r-l>1)
	{
		int mid = (l+r)/2;
		if(check(mid,false))r=mid;
		else l=mid;
	}
	
	if(r==INF)printf("No\n");
	else
	{
		printf("Yes\n");
		check(r,true);
		sort(all(ans));
		ans.erase(unique(all(ans)),ans.end());
		int k=(int)ans.size();
		printf("%d %d\n",r,k);
		for(int i=0;i<k;i++)printf("%d%c",ans[i],(i==k-1)?'\n':' ');
	}
	return 0;
}
