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 = 50005;
struct edge {
  int x, y, c, t;
} edge[Maxn];
vector<int> e[Maxn];
int n, m;
namespace sat {
const int MAXN = 20 * Maxn, MAXM = 40 * Maxn;
int h[MAXN], dfn[MAXN], low[MAXN], bl[MAXN], cnt, scc;
vector<int> son[MAXN];
struct node {
  int to, next;
} e[2 * MAXM];
void reset() {
  for (int i = 1; i <= scc; i++) son[i].clear();
  memset(h, 0, sizeof(h));
  memset(dfn, 0, sizeof(dfn));
  cnt = scc = 0;
}
void AddEdge(int x, int y) {
  e[++cnt] = (node){y, h[x]};
  h[x] = cnt;
}
void tarjan(int x) {
  static int Stack[MAXN], Instack[MAXN], cnt, top;
  dfn[x] = low[x] = ++cnt;
  Stack[++top] = x;
  Instack[x] = true;
  for (int p = h[x]; p; p = e[p].next) {
    int y = e[p].to;
    if (!dfn[y])
      tarjan(y), low[x] = min(low[x], low[y]);
    else if (Instack[y])
      low[x] = min(low[x], dfn[y]);
  }
  if (dfn[x] == low[x]) {
    scc++;
    int t;
    do {
      t = Stack[top--];
      Instack[t] = false;
      son[scc].push_back(t);
      bl[t] = scc;
    } while (t != x);
  }
}
bool solve(int n, int all) {
  for (int i = 1; i <= all; i++)
    if (!dfn[i]) tarjan(i);
  for (int i = 1; i <= n; i++)
    if (bl[2 * i] == bl[2 * i + 1]) return false;
  return true;
}
}  // namespace sat
void link(vector<int> s, int& cnt, int p, int q) {
  if (s.size() < 2) return;
  auto solve = [&]() {
    int pre = 0;
    for (size_t j = 0; j < s.size(); j++) {
      int cur = s[j];
      if (pre) {
        sat::AddEdge(2 * cur + p, pre);
        sat::AddEdge(++cnt, pre);
        pre = cnt;
      } else
        pre = ++cnt;
      sat::AddEdge(pre, 2 * cur + q);
    }
  };
  solve();
  reverse(s.begin(), s.end());
  solve();
}
bool check(int lim) {
  sat::reset();
  int cnt = 2 * m + 1;
  for (int i = 1; i <= m; i++)
    if (edge[i].t > lim) sat::AddEdge(2 * i, 2 * i + 1);
  for (int i = 1; i <= n; i++) {
    link(e[i], cnt, 0, 1);
    for (size_t j = 0, lst = 0; j < e[i].size(); j = lst) {
      while (lst < e[i].size() && edge[e[i][j]].c == edge[e[i][lst]].c) lst++;
      link(vector<int>(e[i].begin() + j, e[i].begin() + lst), cnt, 1, 0);
    }
  }
  return sat::solve(m, cnt);
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; i++) {
    scanf("%d%d%d%d", &edge[i].x, &edge[i].y, &edge[i].c, &edge[i].t);
    e[edge[i].x].push_back(i);
    e[edge[i].y].push_back(i);
  }
  for (int i = 1; i <= n; i++)
    sort(e[i].begin(), e[i].end(),
         [](int a, int b) { return edge[a].c < edge[b].c; });
  int l = 0, r = 1e9;
  while (l <= r) {
    int mid = (l + r) / 2;
    if (check(mid))
      r = mid - 1;
    else
      l = mid + 1;
  }
  if (l > 1e9) return puts("No"), 0;
  check(l);
  vector<int> vec;
  for (int i = 1; i <= sat::cnt; i++) {
    static int vis[Maxn];
    bool chk = true;
    for (int j : sat::son[i])
      if (j <= 2 * m + 1) chk &= !vis[j / 2];
    if (!chk) continue;
    for (int j : sat::son[i])
      if (j <= 2 * m + 1) {
        vis[j / 2] = true;
        if (j % 2 == 0) vec.push_back(j / 2);
      }
  }
  cout << "Yes\n";
  cout << l << " " << vec.size() << "\n";
  for (int i : vec) cout << i << " ";
  cout << "\n";
  return 0;
}
