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 n, m, co, last;
unordered_map<int, pair<int, int>> P[(int)5e4];
int non(int x) {
  if (x < m) return x + m;
  if (x < 2 * m) return x - m;
  if (x & 1) return x - 1;
  return x + 1;
}
void comp_conex(int x, vector<vector<int>>& V, vector<int>& ret,
                vector<int>& st, vector<int>& seen, vector<int>& low,
                int l = 0) {
  seen[x] = 1;
  st.push_back(x);
  low[x] = l;
  for (auto i : V[x])
    if (seen[i] == 0) {
      comp_conex(i, V, ret, st, seen, low, l + 1);
      low[x] = min(low[x], low[i]);
    } else if (seen[i] == 1) {
      low[x] = min(low[x], low[i]);
    }
  if (low[x] == l) {
    int j;
    for (j = st.size() - 1; j >= 0; j--) {
      ret[st[j]] = co;
      seen[st[j]] = 2;
      if (st[j] == x) break;
    }
    st.resize(j);
    co++;
  }
}
bool findval(int x, vector<vector<int>>& V, vector<int>& sol,
             vector<int>& seen) {
  if (sol[x] == 1) return false;
  if (sol[non(x)] == 2) return false;
  seen[x] = 1;
  sol[x] = 2;
  sol[non(x)] = 1;
  for (auto i : V[x])
    if (!seen[i] && !findval(i, V, sol, seen)) return false;
  return true;
}
bool findsol(vector<int>& comp, vector<vector<int>>& incomp,
             vector<vector<int>>& V, vector<int>& sol, vector<int>& seen,
             vector<int>& T, int x) {
  for_each(sol.begin(), sol.end(), [](int& n) { n = 0; });
  for (int j = 0; j < m; j++)
    if (T[j] > x || V[non(j)].size() == 0) {
      sol[j] = 1;
      sol[non(j)] = 2;
    }
  for_each(seen.begin(), seen.end(), [](int& n) { n = 0; });
  for (int i = 0; i < last; i++)
    if (sol[i] == 2 && !seen[i]) {
      if (!findval(i, V, sol, seen)) return false;
    }
  for (auto& i : incomp) {
    if (sol[i[0]] != 0) continue;
    for (auto j : i) {
      sol[j] = 2;
      sol[non(j)] = 1;
    }
  }
  return true;
}
int main() {
  scanf("%d %d", &n, &m);
  vector<vector<int>> V(2 * m);
  vector<int> T(m);
  vector<bool> done(n);
  vector<set<int>> tempV(n);
  for (int i = 0; i < m; i++) {
    int u, v, c, t;
    scanf("%d %d %d %d", &u, &v, &c, &t);
    u--, v--;
    auto inu = P[u].find(c);
    auto inv = P[v].find(c);
    if (inu != P[u].end()) {
      int x = (*inu).second.first;
      if (done[u]) {
        printf("No\n");
        return 0;
      }
      V[non(i)].push_back(x);
      V[non(x)].push_back(i);
      tempV[u].insert(i);
      tempV[u].insert(x);
      tempV[v].insert(i);
      tempV[(*inu).second.second].insert(x);
      done[u] = true;
    } else {
      P[u][c] = {i, v};
    }
    if (inv != P[v].end()) {
      int x = (*inv).second.first;
      if (done[v]) {
        printf("No\n");
        return 0;
      }
      V[non(i)].push_back(x);
      V[non(x)].push_back(i);
      tempV[v].insert(i);
      tempV[v].insert(x);
      tempV[u].insert(i);
      tempV[(*inv).second.second].insert(x);
      done[v] = true;
    } else {
      P[v][c] = {i, u};
    }
    T[i] = t;
  }
  last = 2 * m;
  for (int i = 0; i < n; i++)
    if (tempV[i].size() > 1) {
      V.resize(last + 2);
      auto it = tempV[i].begin();
      int a = *it;
      V[last].push_back(a);
      V[non(a)].push_back(non(last));
      V[non(last)].push_back(non(a));
      V[a].push_back(last);
      last += 2;
      for (++it; it != tempV[i].end(); it++) {
        a = *it;
        V[a].push_back(non(last - 2));
        V[last - 2].push_back(non(a));
        V.resize(last + 2);
        V[non(last)].push_back(non(last - 2));
        V[last - 2].push_back(last);
        V[non(last)].push_back(non(a));
        V[a].push_back(last);
        last += 2;
      }
    }
  vector<int> comp(last);
  vector<int> seen(last);
  vector<int> st;
  vector<int> low(last);
  for_each(comp.begin(), comp.end(), [](int& n) { n = -1; });
  for (int i = 0; i < last; i++)
    if (comp[i] == -1) {
      comp_conex(i, V, comp, st, seen, low);
    }
  for (int i = 0; i < m; i++)
    if (comp[i] == comp[non(i)]) {
      printf("No\n");
      return 0;
    }
  for (int i = 2 * m; i < last; i++)
    if (comp[i] == comp[non(i)]) {
      printf("No\n");
      return 0;
    }
  vector<vector<int>> incomp(co);
  for (int i = 0; i < last; i++) incomp[comp[i]].push_back(i);
  int mt = 0;
  for_each(T.begin(), T.end(), [&mt](int& n) { mt = max(mt, n); });
  vector<int> sol(last);
  int k = 1, i;
  for (; k <= mt; k <<= 1)
    ;
  for (i = -1; k; k >>= 1)
    if (i + k <= mt) {
      int x = i + k;
      bool ok = findsol(comp, incomp, V, sol, seen, T, x);
      if (!ok) i += k;
    }
  i++;
  if (!findsol(comp, incomp, V, sol, seen, T, i)) {
    printf("No\n");
    return 0;
  }
  k = 0;
  for_each(sol.begin(), sol.begin() + m, [&k](int& n) {
    if (n == 2) k++;
  });
  printf("Yes\n");
  printf("%d %d\n", i, k);
  for (int i = 0; i < m; i++)
    if (sol[i] == 2) printf("%d ", i + 1);
  printf("\n");
  return 0;
}
