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 maxn = 100100;
int min_distict = 0;
vector<int> ans;
struct Node {
  int u, v, c, t, id;
  Node() {}
  Node(int u, int v, int c, int t, int id) : u(u), v(v), c(c), t(t), id(id){};
} node[maxn];
bool used[maxn];
int n, m;
bool cmp(Node a, Node b) {
  return a.u < b.u || a.u == b.u && a.v < b.v ||
         a.u == b.u && a.v == b.v && a.c < b.c ||
         a.u == b.u && a.v == b.v && a.c == b.c && a.t < b.t;
}
bool solve() {
  int l = 0;
  while (l < m) {
    int r = l + 1;
    for (; node[l].u == node[r].u && node[l].v == node[r].v; r++)
      ;
    r--;
    int id = -1, cnt = 0;
    for (int i = l; i < r; i++) {
      if (node[i].c == node[i + 1].c) {
        id = i;
        cnt++;
        if (cnt > 1) return false;
      }
    }
    if (id != -1) {
      int u = node[l].u;
      int v = node[l].v;
      if (used[u] || used[v]) return false;
      used[u] = used[v] = true;
      min_distict = max(min_distict, node[id].t);
      ans.push_back(node[id].id);
    }
    l = r + 1;
  }
  return true;
}
void debug() {
  for (int i = 0; i < m; i++) {
    printf("%5d%5d%5d%5d\n", node[i].u, node[i].v, node[i].c, node[i].t);
  }
  printf("size if ans: %d\n", ans.size());
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 0; i < m; i++) {
    int u, v, c, t;
    scanf("%d%d%d%d", &u, &v, &c, &t);
    if (u > v) swap(u, v);
    node[i] = Node(u, v, c, t, i + 1);
  }
  sort(node, node + m, cmp);
  if (solve() == false)
    puts("No");
  else {
    puts("Yes");
    int sz = ans.size();
    printf("%d %d\n", min_distict, sz);
    sort(ans.begin(), ans.end());
    if (sz) printf("%d", ans[0]);
    for (int i = 1; i < sz; i++) printf(" %d", ans[i]);
    puts("");
  }
  return 0;
}
