#include <bits/stdc++.h>
using namespace std;
const int MaxN = 400010, MaxM = 1000010;
class Graph {
 public:
  int en[MaxN], next[MaxM], to[MaxM], tot, deg[MaxN];
  void add_edge(int x, int y) {
    next[++tot] = en[x];
    en[x] = tot;
    to[tot] = y;
    ++deg[y];
  }
  void init() {
    tot = 0;
    memset(en, 0, sizeof en);
    memset(deg, 0, sizeof deg);
  }
} G, T, anti;
struct edge {
  int u, v, c, w;
} E[MaxN];
inline int cmp_col(int a, int b) { return E[a].c < E[b].c; }
int n, m, total;
vector<int> edge[MaxN], ans;
int low[MaxN], dfn[MaxN], dfn_tot, stk[MaxN], stot, scc[MaxN], scc_tot;
bool mark[MaxN];
vector<int> vertex[MaxN];
void failed() {
  puts("No");
  exit(0);
}
bool instk[MaxN];
void dfs(int now) {
  dfn[now] = low[now] = ++dfn_tot;
  stk[++stot] = now;
  instk[now] = 1;
  for (int i = G.en[now]; i; i = G.next[i])
    if (!dfn[G.to[i]]) {
      dfs(G.to[i]);
      low[now] = min(low[now], low[G.to[i]]);
    } else if (instk[G.to[i]])
      low[now] = min(low[now], dfn[G.to[i]]);
  if (dfn[now] == low[now]) {
    int x;
    ++scc_tot;
    do {
      x = stk[stot--];
      instk[x] = 0;
      scc[x] = scc_tot;
      vertex[scc_tot].push_back(x);
    } while (x != now);
  }
}
bool solvable() {
  memset(dfn, 0, sizeof dfn);
  memset(low, 0, sizeof low);
  memset(scc, 0, sizeof scc);
  for (int i = 1; i <= scc_tot; ++i) vertex[i].clear();
  dfn_tot = stot = scc_tot = 0;
  for (int i = 1; i <= total; ++i)
    if (!dfn[i]) dfs(i);
  for (int i = 1; i <= m; ++i)
    if (scc[i * 2] == scc[i * 2 + 1]) return 0;
  return 1;
}
bool done[MaxN];
void settle(int x) {
  if (done[x]) return;
  done[x] = 1;
  for (int i = anti.en[x]; i; i = anti.next[i]) settle(anti.to[i]);
}
void get_ans() {
  T.init();
  anti.init();
  memset(mark, 0, sizeof mark);
  memset(done, 0, sizeof done);
  for (int i = 1; i <= total; ++i)
    for (int j = G.en[i]; j; j = G.next[j])
      if (scc[i] != scc[G.to[j]]) {
        T.add_edge(scc[i], scc[G.to[j]]);
        anti.add_edge(scc[G.to[j]], scc[i]);
      }
  static int q[MaxN];
  int l = 0, r = 0;
  for (int i = 1; i <= scc_tot; ++i)
    if (T.deg[i] == 0) q[++r] = i;
  while (l != r) {
    int u = q[++l];
    for (int i = T.en[u]; i; i = T.next[i])
      if (--T.deg[T.to[i]] == 0) q[++r] = T.to[i];
  }
  for (int i = r; i; --i) {
    int u = q[i];
    if (done[u]) continue;
    done[u] = 1;
    for (auto x : vertex[u]) {
      if (x <= m * 2 + 1) mark[x >> 1] = x & 1;
      settle(scc[x ^ 1]);
    }
  }
  for (int i = 1; i <= m; ++i)
    if (mark[i]) ans.push_back(i);
}
bool check(int x) {
  G.init();
  for (int i = 1; i <= m; ++i)
    if (E[i].w > x) G.add_edge(i * 2 + 1, i * 2);
  total = m * 2;
  for (int i = 1; i <= n; ++i) {
    int sz = edge[i].size(), last = 0;
    for (int j = 0; j < sz - 1; ++j) {
      total += 2;
      int now = total;
      if (last) {
        G.add_edge(last, now);
        G.add_edge(now ^ 1, last ^ 1);
      }
      G.add_edge(edge[i][j] * 2 + 1, now);
      G.add_edge(now + 1, edge[i][j] * 2);
      G.add_edge(now, edge[i][j + 1] * 2);
      G.add_edge(edge[i][j + 1] * 2 + 1, now + 1);
      last = now;
    }
  }
  for (int i = 1; i <= n; ++i) {
    int sz = edge[i].size();
    for (int j = 1; j < sz; ++j)
      if (E[edge[i][j]].c == E[edge[i][j - 1]].c) {
        G.add_edge(edge[i][j] * 2, edge[i][j - 1] * 2 + 1);
        G.add_edge(edge[i][j - 1] * 2, edge[i][j] * 2 + 1);
      }
  }
  return solvable();
}
int main() {
  static int w[MaxN];
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; ++i) {
    scanf("%d%d%d%d", &E[i].u, &E[i].v, &E[i].c, &E[i].w);
    w[i] = E[i].w;
    edge[E[i].u].push_back(i);
    edge[E[i].v].push_back(i);
  }
  for (int i = 1; i <= n; ++i) sort(edge[i].begin(), edge[i].end(), cmp_col);
  for (int i = 1; i <= n; ++i) {
    int cnt = 1, sz = edge[i].size();
    for (int j = 1; j < sz; ++j)
      if (E[edge[i][j]].c != E[edge[i][j - 1]].c)
        cnt = 1;
      else if (++cnt > 2)
        failed();
  }
  sort(w + 1, w + m + 1);
  if (!check(w[m])) failed();
  int l = 0, r = m;
  while (l != r) {
    int mid = (l + r) >> 1;
    if (check(w[mid]))
      r = mid;
    else
      l = mid + 1;
  }
  printf("Yes\n");
  check(w[l]);
  get_ans();
  printf("%d %u\n", w[l], ans.size());
  for (auto x : ans) printf("%d ", x);
  puts("");
  return 0;
}
