#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline bool smin(T &a, const T &b) {
  return b < a ? a = b, 1 : 0;
}
template <typename T>
inline bool smax(T &a, const T &b) {
  return a < b ? a = b, 1 : 0;
}
const int N = (int)5e4 + 10, M = (int)5e5 + 10;
int n, valid[N], cur, res[M], m;
vector<int> g[N], adj[M], rev[M], st, node;
bool mark[M], seen[M];
void reset() {
  cur = m;
  memset(seen, 0, sizeof seen);
  memset(mark, 0, sizeof mark);
  memset(valid, 0, sizeof valid);
  memset(res, 0, sizeof res);
  for (int j = 0; j < M; ++j) {
    adj[j].clear();
    rev[j].clear();
  }
}
struct edges {
  int u, v, c, t;
} edge[N];
inline void addEdge(int u, int v) {
  adj[u].push_back(v);
  rev[v].push_back(u);
}
inline void addClause(int u, int v) {
  addEdge(u ^ 1, v);
  addEdge(v ^ 1, u);
}
int make(vector<int> vc) {
  if (vc.empty()) return -1;
  if ((int)vc.size() == 1) return vc[0];
  int mid = ((int)vc.size()) >> 1;
  vector<int> lc, rc;
  for (int i = 0; i < mid; ++i) lc.push_back(vc[i]);
  for (int i = mid; i < (int)vc.size(); ++i) rc.push_back(vc[i]);
  int L = make(lc);
  int R = make(rc);
  int now = cur++;
  addClause(L << 1, (now << 1) ^ 1);
  addClause(R << 1, (now << 1) ^ 1);
  addClause(L << 1, R << 1);
  return now;
}
void dfs(int v) {
  if (mark[v]++) return;
  for (int u : adj[v]) dfs(u);
  st.push_back(v);
}
void scc(int v) {
  if (mark[v]++) return;
  node.push_back(v);
  seen[v]++;
  for (int u : rev[v]) scc(u);
}
inline bool chk(int mid, bool show = false) {
  cur = m;
  for (int e = 0; e < m; ++e) valid[e] = edge[e].t <= mid;
  for (int i = 0; i < n; ++i) {
    map<int, int> cnt, id;
    for (int e : g[i]) {
      cnt[edge[e].c]++;
      if (cnt[edge[e].c] >= 3) return false;
      if (cnt[edge[e].c] == 2) {
        int other = id[edge[e].c];
        addClause((other << 1) ^ 1, (e << 1) ^ 1);
      }
      id[edge[e].c] = e;
    }
  }
  for (int e = 0; e < m; ++e)
    if (!valid[e]) addEdge((e << 1) ^ 1, e << 1);
  for (int i = 0; i < n; ++i) make(g[i]);
  st.clear();
  for (int i = 0; i < M; ++i)
    if (!mark[i]) dfs(i);
  memset(mark, 0, sizeof mark);
  for (; !st.empty(); st.pop_back()) {
    int v = st.back();
    if (mark[v]) continue;
    node.clear();
    scc(v);
    for (int u : node) {
      if (seen[u ^ 1]) return false;
      res[u >> 1] = (u & 1);
    }
    for (int u : node) seen[u] = false;
  }
  if (show) {
    cout << "Yes\n";
    vector<int> op;
    for (int e = 0; e < m; ++e)
      if (res[e]) op.push_back(e);
    cout << mid << ' ' << (int)op.size() << '\n';
    for (int e : op) cout << ++e << ' ';
    cout << '\n';
  }
  return true;
}
int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> m;
  for (int i = 0; i < m; ++i) {
    cin >> edge[i].u >> edge[i].v >> edge[i].c >> edge[i].t;
    --edge[i].v;
    --edge[i].u;
    int u = edge[i].u;
    int v = edge[i].v;
    g[u].push_back(i);
    g[v].push_back(i);
  }
  int lo = -1, hi = (int)2e9 + 10;
  while (hi - lo > 1) {
    reset();
    int mid = hi + lo >> 1;
    if (chk(mid))
      hi = mid;
    else
      lo = mid;
  }
  reset();
  int okay = chk(hi, true);
  if (!okay) {
    cout << "No\n";
  }
}
