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>
const int MAXN = 2e6 + 7;
struct Edge {
  int s, t, cs, pos;
  bool operator<(const Edge &other) const {
    return s == other.s ? cs < other.cs : s < other.s;
  }
} edge[MAXN];
std::vector<int> E[MAXN];
int n, m, l, r;
int t[MAXN], pre[MAXN], suc[MAXN];
int dfn[MAXN], low[MAXN], mark[MAXN], ts, tot;
std::stack<int> stack;
void Tarjan(int u) {
  dfn[u] = low[u] = ++ts;
  stack.push(u);
  for (int e = 0; e < (int)E[u].size(); e++) {
    int v = E[u][e];
    if (!dfn[v]) {
      Tarjan(v);
      low[u] = std::min(low[u], low[v]);
    } else if (!mark[v])
      low[u] = std::min(low[u], dfn[v]);
  }
  if (dfn[u] == low[u]) {
    tot++;
    while (stack.top() != u) {
      mark[stack.top()] = tot;
      stack.pop();
    }
    mark[u] = tot;
    stack.pop();
  }
}
bool check(int mid) {
  bool flag = true;
  for (int i = 1; i <= m / 2; i++) {
    if (t[i] > mid) E[i].push_back(i + m / 2);
  }
  memset(dfn, 0, sizeof dfn);
  memset(low, 0, sizeof low);
  memset(mark, 0, sizeof low);
  ts = tot = 0;
  for (int i = 1; i <= m; i++)
    if (!dfn[i]) Tarjan(i);
  for (int i = 1; i < m / 2; i++) {
    if (mark[i] == mark[i + m / 2]) {
      flag = false;
      break;
    }
  }
  for (int i = 1; i <= m / 2; i++) {
    if (t[i] > mid) E[i].pop_back();
  }
  return flag;
}
void read(int &x) {
  int flag = 1, ret = 0;
  char c = getchar();
  while (!isdigit(c)) {
    if (c == '-') flag = -1;
    c = getchar();
  }
  while (isdigit(c)) {
    ret = ret * 10 + c - '0';
    c = getchar();
  }
  x = ret * flag;
}
int main() {
  read(n), read(m);
  for (int i = 1; i <= m; i++) {
    read(edge[i].s), read(edge[i].t), read(edge[i].cs), read(t[i]);
    edge[i].pos = i;
    edge[i + m] = edge[i];
    std::swap(edge[i + m].s, edge[i + m].t);
    r = std::max(r, t[i]);
  }
  m <<= 1;
  int tp = m / 2;
  std::sort(edge + 1, edge + m + 1);
  int num = m, j;
  for (int i = 1; i <= m; i = j + 1) {
    pre[i] = ++num, suc[i] = ++num;
    j = i;
    while (j <= m && edge[j + 1].s == edge[i].s &&
           edge[j + 1].cs == edge[j].cs) {
      pre[++j] = ++num, suc[j] = ++num;
    }
    for (int k = i; k <= j; k++) {
      if (k > i)
        E[edge[k].pos + tp].push_back(pre[k - 1]),
            E[pre[k]].push_back(pre[k - 1]);
      if (k < j)
        E[edge[k].pos + tp].push_back(suc[k + 1]),
            E[suc[k]].push_back(suc[k + 1]);
      E[pre[k]].push_back(edge[k].pos);
      E[suc[k]].push_back(edge[k].pos);
    }
  }
  j = 1;
  for (int i = 1; i <= m; i = j + 1) {
    pre[i] = ++num, suc[i] = ++num;
    j = i;
    while (j <= m && edge[j + 1].s == edge[i].s) {
      pre[++j] = ++num, suc[j] = ++num;
    }
    for (int k = i; k <= j; k++) {
      if (k > i)
        E[edge[k].pos].push_back(pre[k - 1]), E[pre[k]].push_back(pre[k - 1]);
      if (k < j)
        E[edge[k].pos].push_back(suc[k + 1]), E[suc[k]].push_back(suc[k + 1]);
      E[pre[k]].push_back(edge[k].pos + tp);
      E[suc[k]].push_back(edge[k].pos + tp);
    }
  }
  int ans = r;
  if (!check(r)) {
    puts("No");
    return 0;
  } else
    puts("Yes");
  while (l <= r) {
    int mid = l + (r - l) / 2;
    if (check(mid))
      r = mid - 1, ans = mid;
    else
      l = mid + 1;
  }
  printf("%d ", ans);
  std::vector<int> v;
  check(ans);
  for (int i = 1; i <= tp; i++) {
    if (mark[i] < mark[i + tp]) v.push_back(i);
  }
  printf("%d\n", v.size());
  for (int i = 1; i <= v.size(); i++) printf("%d ", v[i - 1]);
  puts("");
  return 0;
}
