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>
using namespace std;
int absolut(int x) {
  if (x < 0) return -x;
  return x;
}
int posicion(int x) { return (absolut(x) << 1) - (x < 0); }
int n;
vector<int> g[1000000];
vector<int> ginv[1000000];
vector<int> orden;
int visto[1000000];
int asignacion[1000000];
void generaorden(int u) {
  visto[u] = 1;
  vector<int> &ar = ginv[u];
  for (int i = 0; i < int(ar.size()); i++) {
    int v = ar[i];
    if (not visto[v]) generaorden(v);
  }
  orden.push_back(u);
}
bool marca1(int u) {
  if (visto[u]) return true;
  visto[u] = 1;
  if (((u & 1) == 0 and visto[u - 1] == 1) or
      ((u & 1) == 1 and visto[u + 1] == 1))
    return false;
  vector<int> &ar = g[u];
  for (int i = 0; i < int(ar.size()); i++) {
    int v = ar[i];
    if (not marca1(v)) return false;
  }
  return true;
}
void marca2(int u) {
  if (visto[u] == 2) return;
  visto[u] = 2;
  vector<int> &ar = g[u];
  for (int i = 0; i < int(ar.size()); i++) {
    int v = ar[i];
    marca2(v);
  }
}
bool satisfactible() {
  orden = vector<int>();
  for (int i = 1; i <= n; i++) visto[i] = 0;
  for (int i = 1; i <= n; i++)
    if (not visto[i]) generaorden(i);
  reverse(orden.begin(), orden.end());
  for (int i = 1; i <= n; i++) visto[i] = 0;
  for (int i = 0; i < int(orden.size()); i++) {
    int u = orden[i];
    if (not marca1(u)) return false;
    marca2(u);
  }
  return true;
}
void asignar(int u, int val) {
  if (visto[u]) return;
  visto[u] = 1;
  asignacion[u] = val;
  vector<int> &ar = g[u];
  for (int i = 0; i < int(ar.size()); i++) {
    int v = ar[i];
    asignar(v, val);
  }
}
void asignar() {
  for (int i = 1; i <= n; i++) visto[i] = 0;
  for (int i = 0; i < int(orden.size()); i++) {
    int u = orden[i];
    if (not visto[u]) {
      if (((u & 1) == 0 and visto[u - 1] == 1) or
          ((u & 1) == 1 and visto[u + 1] == 1))
        asignar(u, 0);
      else
        asignar(u, 1);
    }
  }
}
void flecha(int x, int y) {
  g[posicion(x)].push_back(posicion(y));
  ginv[posicion(y)].push_back(posicion(x));
}
void clausula(int x, int y) {
  flecha(-x, y);
  flecha(-y, x);
}
struct arista {
  int u, v, c, t;
};
int m;
arista va[100001];
vector<int> inciden[100001];
map<int, vector<int> > c2i[100001];
bool puede(int nn, int t) {
  for (int i = 1; i <= 400000; i++) g[i] = ginv[i] = vector<int>();
  for (int i = 1; i <= m; i++) {
    arista &a = va[i];
    if (t < a.t) flecha(i, -i);
  }
  n = m;
  for (int i = 1; i <= nn; i++) {
    map<int, vector<int> > &mc2i = c2i[i];
    for (map<int, vector<int> >::iterator it = mc2i.begin(); it != mc2i.end();
         it++) {
      vector<int> &vec = it->second;
      if (int(vec.size()) == 2) clausula(vec[0], vec[1]);
    }
    vector<int> &vec = inciden[i];
    if (int(vec.size()) >= 2) {
      for (int j = 0; j < int(vec.size()) - 1; j++) {
        int u = vec[j];
        int v = vec[j + 1];
        clausula(-u, n + 1 + j);
        clausula(-(n + 1 + j), -v);
        if (j > 0) clausula(-(n + 1 + j - 1), n + 1 + j);
      }
      n += int(vec.size()) - 1;
    }
  }
  n *= 2;
  return satisfactible();
}
int main() {
  int n;
  cin >> n >> m;
  set<int> stiempos;
  stiempos.insert(0);
  for (int i = 1; i <= m; i++) {
    arista &a = va[i];
    cin >> a.u >> a.v >> a.c >> a.t;
    stiempos.insert(a.t);
    inciden[a.u].push_back(i);
    inciden[a.v].push_back(i);
    c2i[a.u][a.c].push_back(i);
    c2i[a.v][a.c].push_back(i);
    if (int(c2i[a.u][a.c].size()) > 2 or int(c2i[a.v][a.c].size()) > 2) {
      cout << "No" << endl;
      exit(0);
    }
  }
  vector<int> tiempos;
  for (set<int>::iterator it = stiempos.begin(); it != stiempos.end(); it++)
    tiempos.push_back(*it);
  int inf = -1;
  int sup = int(tiempos.size());
  while (inf + 1 < sup) {
    int med = (inf + sup) / 2;
    if (puede(n, tiempos[med]))
      sup = med;
    else
      inf = med;
  }
  if (sup == int(tiempos.size())) {
    cout << "No" << endl;
  } else {
    cout << "Yes" << endl;
    puede(n, tiempos[sup]);
    asignar();
    vector<int> sol;
    for (int i = 1; i <= n; i++)
      if (asignacion[2 * i]) sol.push_back(i);
    cout << tiempos[sup] << " " << int(sol.size()) << endl;
    for (int i = 0; i < int(sol.size()); i++) {
      if (i > 0) cout << " ";
      cout << sol[i];
    }
    cout << endl;
  }
}
