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>
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("O3")
#pragma GCC optimize("fast-math")
#pragma GCC optimize("Ofast")
using namespace std;
const int INF = 1e9 + 10;
const long long INFll = 2e18;
const int BASE1 = 179;
const int BASE2 = 653;
const long long MOD = 998244353;
const int MAXA = 2000001;
const int MAXN = 2e5 + 1;
const int MAXLOG = 22;
const long long COST = 1000 * 1000 * 1000;
const long double PI = 3.1415926535;
const long double EPS = 1e-15;
struct edge {
  int to, col, t, i;
  edge(int a, int b, int c, int d) {
    to = a;
    col = b;
    t = c;
    i = d;
  }
};
int n, m;
vector<vector<edge>> g;
vector<pair<int, edge>> edges;
int notv(int v, int cnt) { return v + cnt; }
void add_edge(int u, int v, vector<vector<int>>& g, vector<vector<int>>& rg) {
  g[u].emplace_back(v);
  rg[v].emplace_back(u);
}
bool cmp(edge& a, edge& b) { return a.col < b.col; }
void dfs1(int v, vector<vector<int>>& g, vector<int>& used,
          vector<int>& order) {
  used[v] = true;
  for (auto u : g[v]) {
    if (!used[u]) dfs1(u, g, used, order);
  }
  order.emplace_back(v);
}
void dfs2(int v, vector<vector<int>>& g, vector<int>& comp, int now) {
  comp[v] = now;
  for (auto u : g[v]) {
    if (comp[u] == -1) dfs2(u, g, comp, now);
  }
}
pair<bool, vector<int>> SAT(vector<vector<int>>& sat1,
                            vector<vector<int>>& sat2) {
  int n1 = ((int)(sat1).size());
  int dopcnt = n1 / 2;
  vector<int> used(n1), order;
  for (int v = 0; v < (n1); v++) {
    if (!used[v]) dfs1(v, sat1, used, order);
  }
  reverse(order.begin(), order.end());
  vector<int> comp(n1, -1);
  int nowcomp = 0;
  for (auto v : order) {
    if (comp[v] == -1) {
      dfs2(v, sat2, comp, nowcomp++);
    }
  }
  for (int v = 0; v < (n1 / 2); v++) {
    if (comp[v] == comp[notv(v, dopcnt)])
      return make_pair(false, vector<int>(0));
  }
  vector<int> res;
  for (int e = 0; e < (n1 / 6); e++) {
    if (comp[e] > comp[notv(e, dopcnt)]) res.emplace_back(e);
  }
  return make_pair(true, res);
}
pair<bool, vector<int>> check(int time) {
  vector<vector<int>> sat1(6 * m), sat2(6 * m);
  int dopcnt = 3 * m;
  for (int i = 0; i < (m); i++) {
    if (edges[i].second.t > time) {
      add_edge(i, notv(i, dopcnt), sat1, sat2);
      add_edge(i, notv(i, dopcnt), sat1, sat2);
    }
  }
  int now = m;
  for (int v = 0; v < (n); v++) {
    for (int i = 0; i < (((int)(g[v]).size()) - 1); i++) {
      if (i > 0 && g[v][i - 1].col == g[v][i].col &&
          g[v][i + 1].col == g[v][i].col)
        return make_pair(false, vector<int>(0));
      if (g[v][i + 1].col == g[v][i].col) {
        int i1 = g[v][i].i, i2 = g[v][i + 1].i;
        add_edge(notv(i1, dopcnt), i2, sat1, sat2);
        add_edge(notv(i2, dopcnt), i1, sat1, sat2);
      }
    }
    for (int i = 0; i < (((int)(g[v]).size())); i++) {
      int d = now + i, e = g[v][i].i;
      add_edge(e, d, sat1, sat2);
      add_edge(notv(d, dopcnt), notv(e, dopcnt), sat1, sat2);
      if (i > 0) {
        add_edge(d - 1, notv(e, dopcnt), sat1, sat2);
        add_edge(e, notv(d - 1, dopcnt), sat1, sat2);
        add_edge(d - 1, d, sat1, sat2);
        add_edge(notv(d, dopcnt), notv(d - 1, dopcnt), sat1, sat2);
      }
    }
    now += ((int)(g[v]).size());
  }
  return SAT(sat1, sat2);
}
void solve() {
  cin >> n >> m;
  g.resize(n);
  for (int i = 0; i < (m); i++) {
    int v, u, c, t;
    cin >> v >> u >> c >> t;
    v--;
    u--;
    edges.emplace_back(make_pair(v, edge(u, c, t, i)));
    g[v].emplace_back(edge(u, c, t, i));
    g[u].emplace_back(edge(v, c, t, i));
  }
  for (int v = 0; v < (n); v++) sort(g[v].begin(), g[v].end(), cmp);
  int left = -1, right = 1e9 + 1;
  while (right - left > 1) {
    int mid = (left + right) / 2;
    if (check(mid).first)
      right = mid;
    else
      left = mid;
  }
  auto dop = check(right);
  if (dop.first) {
    cout << "Yes\n";
    vector<int> res = dop.second;
    cout << right << " " << ((int)(res).size()) << "\n";
    for (int i = 0; i < (((int)(res).size())); i++) cout << res[i] + 1 << " ";
    cout << "\n";
  } else {
    cout << "No\n";
  }
}
signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cout << fixed << setprecision(15);
  int t = 1;
  while (t--) solve();
  return 0;
}
