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 long N = 5 * 10000 + 7;
const long INF = 1000000000 + 7;
const long MODULE = 1000000000 + 7;
class TwosatSolver {
 public:
  struct pair_hash {
    template <class T1, class T2>
    std::size_t operator()(std::pair<T1, T2> const &pair) const {
      std::size_t h1 = std::hash<T1>()(pair.first);
      std::size_t h2 = std::hash<T2>()(pair.second);
      return h1 ^ h2;
    }
  };
  int nov;
  int cnt;
  bool Invalid;
  int *color, *num, *low;
  vector<int> *edges;
  stack<int> s;
  unordered_set<pair<int, int>, pair_hash> cedges;
  TwosatSolver(int n) {
    this->nov = n;
    edges = double_calloc<vector<int> >(n * 2 + 5);
    color = double_calloc<int>(n * 2 + 5);
    num = double_calloc<int>(n * 2 + 5);
    low = double_calloc<int>(n * 2 + 5);
    init();
  }
  void init() {
    cnt = 0;
    Invalid = false;
    while (!s.empty()) s.pop();
    for (int i = -nov; i <= nov; i++) {
      num[i] = low[i] = color[i] = 0;
    }
  }
  int no_edges() { return cedges.size(); }
  void display_edges() {
    cout << "----Begin show edges----\n";
    for (unordered_set<pair<int, int>, pair_hash>::iterator it = cedges.begin();
         it != cedges.end(); ++it)
      cout << it->first << " " << it->second << endl;
    cout << "----End show edges----\n";
  }
  void shrink(int n) { this->nov = n; }
  template <class T>
  T *double_calloc(int n) {
    return ((T *)calloc(n, sizeof(T))) + (n) / 2;
  }
  void add_clause(int u, int v) {
    assert((u >= -nov) and (u <= nov));
    assert((v >= -nov) and (v <= nov));
    if (!cedges.count(pair<int, int>(-u, v)))
      edges[-u].push_back(v), cedges.insert(pair<int, int>(-u, v));
    if (!cedges.count(pair<int, int>(-v, u)))
      edges[-v].push_back(u), cedges.insert(pair<int, int>(-v, u));
  }
  void add_implication(int u, int v) {
    assert((u >= -nov) and (u <= nov));
    assert((v >= -nov) and (v <= nov));
    if (!cedges.count(pair<int, int>(u, v)))
      edges[u].push_back(v), cedges.insert(pair<int, int>(u, v));
  }
  void set_color(int u, int x) {
    if (color[u] == (x ^ 3))
      Invalid = true;
    else
      color[u] = x;
    if (color[-u] == x)
      Invalid = true;
    else
      color[-u] = (x ^ 3);
  }
  void dfs(int u) {
    num[u] = low[u] = ++cnt;
    s.push(u);
    for (auto v : edges[u]) {
      if (num[v]) {
        low[u] = min(low[u], num[v]);
      } else {
        dfs(v);
        low[u] = min(low[u], low[v]);
      }
      if (color[v] == 1) set_color(u, 1);
    }
    if (low[u] == num[u]) {
      int v = 0;
      if (color[u] == 0) set_color(u, 2);
      do {
        v = s.top();
        s.pop();
        set_color(v, color[u]);
        num[v] = low[v] = 0x33334444;
      } while (u != v);
    }
  }
  bool solve(vector<int> &ret) {
    for (int i = 1; i <= nov; i++)
      if (!num[i]) dfs(i);
    for (int i = 1; i < nov; i++)
      if (!num[i]) dfs(-i);
    if (Invalid) return false;
    for (int i = 1; i <= nov; i++)
      if (color[i] == 2) {
        ret.push_back(i);
      }
    return true;
  }
};
struct Edge {
  int v, c, t, id;
  Edge(int v, int c, int t, int id) {
    this->v = v;
    this->c = c;
    this->t = t;
    this->id = id;
  }
};
int n, m;
vector<Edge> a[N];
unordered_map<int, int> mc;
bool check(int mt, vector<int> &res) {
  TwosatSolver twosat = TwosatSolver(3 * m);
  int curp = m + 1;
  for (int u = 1; u <= n; u++) {
    mc.clear();
    bool chose = false;
    for (int i = 0; i < a[u].size(); i++) {
      Edge e = a[u][i];
      if (e.t > mt) {
        twosat.set_color(e.id, 1);
      }
      if (!mc.count(e.c)) {
        mc[e.c] = e.id;
      } else {
        if (chose) return false;
        chose = true;
        twosat.add_clause(e.id, mc[e.c]);
      }
      twosat.add_clause(curp, -e.id);
      if (i != 0) twosat.add_clause(-(curp - 1), curp);
      if (i != a[u].size() - 1) twosat.add_clause(-curp, -a[u][i + 1].id);
      ++curp;
    }
  }
  res.clear();
  bool ret = twosat.solve(res);
  return ret;
}
int main() {
  cin >> n >> m;
  for (int i = 1; i <= m; i++) {
    int u, v, c, t;
    cin >> u >> v >> c >> t;
    a[u].push_back(Edge(v, c, t, i));
    a[v].push_back(Edge(u, c, t, i));
  }
  vector<int> res;
  int l = 0, r = INF;
  while (l < r - 1) {
    int mid = (l + r) / 2;
    if (check(mid, res))
      r = mid;
    else
      l = mid;
  }
  if (!check(r, res)) {
    cout << "NO" << endl;
  } else {
    cout << "YES" << endl;
    cout << r << " ";
    int cnt = 0;
    for (auto e : res)
      if (e <= m) ++cnt;
    cout << cnt << endl;
    for (auto e : res)
      if (e <= m) cout << e << " ";
  }
  return 0;
}
