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;
long long rdtsc() {
  long long tmp;
  asm("rdtsc" : "=A"(tmp));
  return tmp;
}
inline int myrand() { return abs((rand() << 15) ^ rand()); }
inline int rnd(int x) { return myrand() % x; }
const int INF = (int)1.01e9;
const long double EPS = 1e-9;
void precalc() {}
const int maxn = (int)5e4 + 10, maxm = 2 * maxn;
int mhead[maxn];
int mnext[maxm];
int to[maxm];
int cnte;
void adde(int s, int t) {
  mnext[cnte] = mhead[s];
  mhead[s] = cnte;
  to[cnte] = t;
  ++cnte;
}
int col[maxn];
int times[maxn];
int n, m;
bool read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return 0;
  }
  cnte = 0;
  for (int i = 0; i < n; ++i) {
    mhead[i] = -1;
  }
  for (int i = 0; i < m; ++i) {
    int s, t, c, tme;
    scanf("%d%d%d%d", &s, &t, &c, &tme);
    --s, --t;
    col[i] = c, times[i] = tme;
    adde(s, t);
    adde(t, s);
  }
  return 1;
}
int goEdge[maxm];
int used[maxn];
vector<pair<int, vector<vector<int> > > > groups;
int ans[maxn];
int res;
pair<int, pair<int, int> > vs[maxn];
int dead[maxn];
bool solve(int weight) {
  res = 0;
  for (int i = 0; i < n; ++i) {
    dead[i] = 0;
  }
  int cnt = 0;
  for (int i = 0; i < ((int)(groups).size()); ++i) {
    int type = groups[i].first;
    const vector<vector<int> > &group = groups[i].second;
    assert(((int)(group).size()) == 2);
    int mask = 0;
    for (int i = 0; i < 2; ++i) {
      bool fail = 0;
      for (int j = 0; j < ((int)(group[i]).size()); ++j) {
        int e = group[i][j];
        if (times[e / 2] > weight) {
          fail = 1;
          break;
        }
      }
      if (!fail) {
        mask ^= (1 << i);
      }
    }
    if (!mask) {
      return 0;
    }
    if (mask == 3) {
      if (type == 0) {
        if ((((int)(group[0]).size()) + ((int)(group[1]).size())) & 1) {
          mask = 2;
        }
      } else {
        mask = 1;
      }
    }
    if (mask != 3) {
      int odd = (mask == 1 ? 0 : 1);
      for (int i = 0; i < ((int)(group[odd]).size()); ++i) {
        int edge = group[odd][i];
        ++dead[to[edge]], ++dead[to[edge ^ 1]];
        ans[res++] = edge / 2;
      }
      continue;
    }
    assert(!type);
    for (int i = 0; i < ((int)(group[0]).size()); ++i) {
      int edge = group[0][i];
      ++dead[to[edge]];
      if (i) {
        ++dead[to[edge ^ 1]];
      }
    }
    vs[cnt++] =
        make_pair(i, make_pair(to[group[0][0] ^ 1], to[group[1].back()]));
  }
  if (*max_element(dead, dead + n) >= 2) {
    return 0;
  }
  for (int i = 0; i < cnt; ++i) {
    int s = vs[i].second.first, t = vs[i].second.second;
    if (dead[s] || dead[t]) {
      return 0;
    }
  }
  vector<vector<int> > es(n);
  vector<vector<int> > num(n);
  vector<int> deg(n, 0);
  for (int i = 0; i < cnt; ++i) {
    int s = vs[i].second.first, t = vs[i].second.second;
    es[s].push_back(t), es[t].push_back(s);
    num[s].push_back(i + 1), num[t].push_back(-(i + 1));
    ++deg[s], ++deg[t];
  }
  vector<int> st;
  for (int i = 0; i < n; ++i) {
    if (deg[i] == 1) {
      st.push_back(i);
    }
  }
  vector<int> orient(cnt, -1);
  for (int l = 0; l < ((int)(st).size()); ++l) {
    int v = st[l];
    if (!deg[v]) {
      continue;
    }
    assert(deg[v] == 1);
    for (int it = 0; it < ((int)(es[v]).size()); ++it) {
      int u = es[v][it];
      int eid = num[v][it];
      int rid = abs(eid) - 1;
      if (orient[rid] != -1) {
        continue;
      }
      orient[rid] = (eid > 0 ? 0 : 1);
      --deg[v], --deg[u];
      if (deg[u] == 1) {
        st.push_back(u);
      }
    }
    assert(!deg[v]);
  }
  for (int i = 0; i < n; ++i) {
    if (deg[i] != 2 && deg[i]) {
      return 0;
    }
  }
  for (int i = 0; i < n; ++i) {
    if (deg[i]) {
      int last = -1;
      for (int v = i;;) {
        assert(deg[v] == 2);
        deg[v] = 0;
        int u = -1;
        for (int it = 0; it < ((int)(es[v]).size()); ++it) {
          u = es[v][it];
          int eid = num[v][it];
          int rid = abs(eid) - 1;
          if (orient[rid] != -1) {
            u = -1;
            continue;
          }
          orient[rid] = (eid > 0 ? 0 : 1);
          break;
        }
        assert(u != -1);
        v = u;
        if (v == i) {
          break;
        }
      }
    }
  }
  for (int i = 0; i < cnt; ++i) {
    const vector<vector<int> > &group = groups[vs[i].first].second;
    assert(((int)(group).size()) == 2);
    int odd = orient[i];
    for (int i = 0; i < ((int)(group[odd]).size()); ++i) {
      int edge = group[odd][i];
      ans[res++] = edge / 2;
    }
  }
  return 1;
}
void solve() {
  for (int i = 0; i < cnte; ++i) {
    goEdge[i] = -1;
  }
  for (int i = 0; i < n; ++i) {
    vector<pair<int, int> > edges;
    for (int e = mhead[i]; e != -1; e = mnext[e]) {
      edges.push_back(make_pair(col[e / 2], e));
    }
    sort(edges.begin(), edges.end());
    for (int i = 0; i < ((int)(edges).size());) {
      int i0 = i;
      while (i < ((int)(edges).size()) && edges[i].first == edges[i0].first) {
        ++i;
      }
      if (i - i0 > 2) {
        printf("No\n");
        return;
      }
      if (i - i0 == 2) {
        int e1 = edges[i0].second, e2 = edges[i0 + 1].second;
        goEdge[e1 ^ 1] = e2;
        goEdge[e2 ^ 1] = e1;
      }
    }
  }
  for (int e = 0; e < m; ++e) {
    used[e] = 0;
  }
  groups.clear();
  for (int iter = 0; iter < 2; ++iter) {
    for (int e = 0; e < cnte; ++e) {
      if (used[e / 2]) {
        continue;
      }
      if (!iter && goEdge[e ^ 1] != -1) {
        continue;
      }
      vector<int> cur;
      for (int ce = e; ce != -1 && !used[ce / 2]; ce = goEdge[ce]) {
        cur.push_back(ce);
        used[ce / 2] = 1;
      }
      if (iter && (((int)(cur).size()) & 1)) {
        printf("No\n");
        return;
      }
      vector<vector<int> > group;
      for (int odd = 0; odd < 2; ++odd) {
        vector<int> toadd;
        for (int i = odd; i < ((int)(cur).size()); i += 2) {
          toadd.push_back(cur[i]);
        }
        group.push_back(toadd);
      }
      groups.push_back(make_pair(iter, group));
    }
  }
  int l = -1, r = INF;
  while (l + 1 < r) {
    int mid = (l + r) / 2;
    if (solve(mid)) {
      r = mid;
    } else {
      l = mid;
    }
  }
  if (r == INF) {
    printf("No\n");
    return;
  }
  assert(solve(r));
  printf("Yes\n");
  printf("%d %d\n", r, res);
  for (int i = 0; i < res; ++i) {
    printf("%d%c", ans[i] + 1, " \n"[i == res - 1]);
  }
}
int main() {
  srand(rdtsc());
  precalc();
  while (1) {
    if (!read()) {
      break;
    }
    solve();
  }
  return 0;
}
