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++] = t;
    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;
}
int solve() {
  int Max = 0;
  int ans[MX], ans1[MX], ans2[MX], an = 0, an1 = 0, an2 = 0, Max1, Max2;
  for (int i = 0; i < N; i++)
    if (chk[i] == -1) {
      for (auto it : con[i]) {
        int u = edge[it].Find(i);
        if (chk[u] == -1) continue;
        if (chk[u] != edge[it].c) continue;
        an1 = an2 = Max1 = Max2 = 0;
        int bf = 1, now = it;
        ans1[an1++] = it, Max1 = edge[it].t;
        while (true) {
          now = ege[u][0] == now ? ege[u][1] : ege[u][0];
          if (now == it && bf == 1) return false;
          if (now == it) break;
          if (bf == 1)
            ans2[an2++] = now, Max2 = max(Max2, edge[now].t);
          else
            ans1[an1++] = now, Max1 = max(Max1, edge[now].t);
          u = edge[now].Find(u);
          if (chk[u] == -1) break;
          if (chk[u] != edge[now].c) break;
          bf = !bf;
        }
        if (Max1 < Max2)
          for (int j = 0; j < an1; j++) ans[an++] = ans1[j];
        else
          for (int j = 0; j < an2; j++) ans[an++] = ans2[j];
        Max = max(Max, min(Max1, Max2));
      }
    }
  for (int i = 0; i < N; i++)
    if (chk[i] != -1) {
      int u = ege[i][0], v = ege[i][1];
      if (edge[u].Find(i) == edge[v].Find(i)) {
        if (edge[u].t < edge[v].t)
          ans[an++] = u;
        else
          ans[an++] = v;
        Max = max(Max, min(edge[u].t, edge[v].t));
      }
    }
  puts("Yes");
  printf("%d %d\n", X[Max], an);
  sort(ans, ans + an);
  an = unique(ans, ans + an) - ans;
  for (int i = 0; i < an; i++) printf("%d%c", ans[i], i < an - 1 ? ' ' : '\n');
  return true;
}
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].t = lower_bound(X, X + Xn, edge[i].t) - X;
  if (!isGood()) {
    puts("No");
    return 0;
  }
  if (!solve()) {
    puts("No");
    return 0;
  }
  return 0;
}
