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;
template <typename T>
bool chkmin(T &x, T y) {
  return x > y ? x = y, 1 : 0;
}
template <typename T>
bool chkmax(T &x, T y) {
  return x < y ? x = y, 1 : 0;
}
int readint() {
  int x = 0, f = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    x = x * 10 + ch - '0';
    ch = getchar();
  }
  return x * f;
}
struct edge {
  int u, v, c, t;
} e[50005];
int n, m, tot, ncnt, scnt, cnt;
int v[500005], nxt[500005], h[200005], dfn[200005], low[200005], col[200005];
bool ins[200005];
stack<int> s;
vector<int> adj[50005], res;
map<int, int> b[50005];
void addedge(int x, int y) {
  v[++tot] = y;
  nxt[tot] = h[x];
  h[x] = tot;
}
void tarjan(int u) {
  dfn[u] = low[u] = ++ncnt;
  s.push(u);
  ins[u] = true;
  for (int p = h[u]; p; p = nxt[p]) {
    if (!dfn[v[p]])
      tarjan(v[p]), chkmin(low[u], low[v[p]]);
    else if (ins[v[p]])
      chkmin(low[u], dfn[v[p]]);
  }
  if (low[u] == dfn[u]) {
    scnt++;
    do {
      col[u] = scnt;
      u = s.top();
      s.pop();
      ins[u] = false;
    } while (dfn[u] != low[u]);
  }
}
bool check(int x, bool kp) {
  for (int i = 1; i <= n; i++) b[i].clear(), adj[i].clear();
  memset(h, 0, sizeof(h));
  tot = 0, cnt = m;
  for (int i = 1; i <= m; i++) {
    if (e[i].t > x) {
      b[e[i].u][e[i].c]++, b[e[i].v][e[i].c]++;
      if (b[e[i].u][e[i].c] == 2 || b[e[i].v][e[i].c] == 2) return false;
      addedge(i + cnt, i);
      continue;
    } else
      adj[e[i].u].push_back(e[i].v), adj[e[i].v].push_back(e[i].u);
  }
  for (int i = 1; i <= n; i++) cnt += adj[i].size() << 1;
  int nowcnt = m;
  for (int i = 1; i <= n; i++) {
    if (adj[i].size()) addedge(nowcnt + 1 + cnt, adj[i][0]);
    for (int j = 1; j < (int)adj[i].size(); j++) {
      addedge(nowcnt + j + 1 + cnt, nowcnt + j + cnt);
      addedge(nowcnt + j + 1 + cnt, adj[i][j]);
    }
    if (adj[i].size())
      addedge(nowcnt + adj[i].size() * 2 + cnt, adj[i][adj[i].size() - 1]);
    for (int j = 0; j < (int)adj[i].size() - 1; j++) {
      addedge(nowcnt + adj[i].size() + j + 1 + cnt,
              nowcnt + adj[i].size() + j + 2 + cnt);
      addedge(nowcnt + adj[i].size() + j + 1 + cnt, adj[i][j]);
    }
    nowcnt += adj[i].size() << 1;
  }
  for (int i = 1; i <= n; i++) b[i].clear();
  for (int i = 1; i <= m; i++) {
    if (b[e[i].u].count(e[i].c))
      addedge(b[e[i].u][e[i].c], i + cnt), addedge(b[e[i].u][e[i].c] + cnt, i),
          addedge(i, b[e[i].u][e[i].c] + cnt),
          addedge(i + cnt, b[e[i].u][e[i].c]);
    else
      b[e[i].u][e[i].c] = i;
  }
  memset(dfn, 0, sizeof(dfn));
  ncnt = scnt = 0;
  memset(ins, 0, sizeof(ins));
  memset(col, 0, sizeof(col));
  for (int i = 1; i <= cnt + cnt; i++)
    if (!dfn[i]) tarjan(i);
  for (int i = 1; i <= cnt; i++)
    if (col[i] == col[i + cnt]) return false;
  if (kp) {
    for (int i = 1; i <= m; i++)
      if (e[i].t <= x && col[i] < col[i + cnt]) res.push_back(i);
    printf("%d %d\n", x, (int)res.size());
    for (auto r : res) printf("%d ", r);
    printf("\n");
  }
  return true;
}
int main() {
  n = readint();
  m = readint();
  for (int i = 1; i <= m; i++)
    e[i].u = readint(), e[i].v = readint(), e[i].c = readint(),
    e[i].t = readint();
  for (int i = 1; i <= m; i++) {
    b[e[i].u][e[i].c]++, b[e[i].v][e[i].c]++;
    if (b[e[i].u][e[i].c] > 2 || b[e[i].v][e[i].c] > 2)
      return printf("No\n"), 0;
  }
  int l = 1, r = 1e9 + 10, ans = 0;
  while (l <= r) {
    int mid = (l + r) / 2;
    if (check(mid, 0))
      ans = mid, r = mid - 1;
    else
      l = mid + 1;
  }
  if (!ans) return printf("No\n"), 0;
  printf("Yes\n");
  check(ans, 1);
  return 0;
}
