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;
const int MX = 50005;
int N, M;
int X[MX], Xn;
vector<int> con[MX];
struct Edge {
  int u, v, id;
  int c, t;
  Edge(int u = 0, int v = 0) : u(u), v(v) {}
  bool operator<(const Edge &D) const { return t < D.t; }
  void in() {
    scanf("%d%d%d%d", &u, &v, &c, &t);
    u--, v--, X[Xn++] = c;
    con[u].push_back(id), con[v].push_back(id);
  }
  int Find(int uu) { return uu == u ? v : u; }
} edge[MX];
int chk[MX], ege[MX][2];
bool isGood() {
  int frq[MX] = {0};
  for (int i = 0; i < N; i++) {
    int cnt = 0, cc = -1;
    for (auto it : con[i]) {
      if (frq[edge[it].c] == i + 1) cnt++, cc = edge[it].c;
      frq[edge[it].c] = i + 1;
    }
    if (cnt > 1) return false;
    chk[i] = cc;
    int nn = 0;
    for (auto it : con[i])
      if (edge[it].c == cc) ege[i][nn++] = it;
  }
  return true;
}
bool solve() {
  int vis[MX] = {0};
  int ans[5 * MX], an = 0, tot = 0;
  int res[2][MX], rn[2], Max[2];
  for (int i = 0; i < N; i++)
    if (chk[i] == -1) {
      vis[i] = true;
      for (auto it : con[i]) {
        int u = edge[it].Find(i);
        if (chk[u] != edge[it].c) continue;
        vis[u] = true;
        int now = it, id = 0;
        rn[0] = rn[1] = Max[0] = Max[1] = 0;
        res[id][rn[id]++] = now, Max[id] = edge[it].t;
        while (true) {
          id = !id;
          now = ege[u][0] == now ? ege[u][1] : ege[u][0];
          res[id][rn[id]++] = now, Max[id] = max(Max[id], edge[now].t);
          u = edge[now].Find(u);
          vis[u] = true;
          if (chk[u] != edge[now].c) break;
        }
        tot = max(tot, min(Max[0], Max[1]));
        id = Max[1] < Max[0];
        for (int j = 0; j < rn[id]; j++) ans[an++] = res[id][j];
      }
    }
  for (int i = 0; i < N; i++)
    if (!vis[i]) {
      int it = ege[i][0];
      int u = edge[it].Find(i);
      vis[i] = vis[u] = true;
      int now = it, id = 0;
      rn[0] = rn[1] = Max[0] = Max[1] = 0;
      res[id][rn[id]++] = now, Max[id] = edge[it].t;
      while (true) {
        id = !id;
        now = ege[u][0] == now ? ege[u][1] : ege[u][0];
        if (now == it && id == 1) return false;
        if (now == it) break;
        res[id][rn[id]++] = now, Max[id] = max(Max[id], edge[now].t);
        u = edge[now].Find(u);
        vis[u] = true;
        if (chk[u] != edge[now].c) break;
      }
      tot = max(tot, min(Max[0], Max[1]));
      id = Max[1] < Max[0];
      for (int j = 0; j < rn[id]; j++) ans[an++] = res[id][j];
    }
  sort(ans, ans + an);
  an = unique(ans, ans + an) - ans;
  puts("Yes");
  printf("%d %d\n", tot, an);
  for (int i = 0; i < an; i++) printf("%d%c", ans[i], i < an - 1 ? ' ' : '\n');
}
int main() {
  for (int i = 0; i < MX; i++) edge[i].id = i;
  scanf("%d%d", &N, &M);
  for (int i = 1; i <= M; i++) edge[i].in();
  sort(X, X + Xn);
  Xn = unique(X, X + Xn) - X;
  for (int i = 1; i <= M; i++)
    edge[i].c = lower_bound(X, X + Xn, edge[i].c) - X;
  if (!isGood()) {
    puts("No");
    return 0;
  }
  if (!solve()) {
    puts("No");
    return 0;
  }
  return 0;
}
