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;
template <class T, class S>
ostream& operator<<(ostream& os, const pair<T, S>& v) {
  return os << "(" << v.first << ", " << v.second << ")";
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& v) {
  os << "[";
  for (int i = int(0); i <= int((static_cast<int>((v).size())) - 1); ++i) {
    if (i) os << ", ";
    os << v[i];
  }
  return os << "]";
}
template <class T>
bool setmax(T& _a, T _b) {
  if (_a < _b) {
    _a = _b;
    return true;
  }
  return false;
}
template <class T>
bool setmin(T& _a, T _b) {
  if (_b < _a) {
    _a = _b;
    return true;
  }
  return false;
}
template <class T>
T gcd(T _a, T _b) {
  return _b == 0 ? _a : gcd(_b, _a % _b);
}
namespace two_sat {
const int N = 3000000;
vector<int> es[N];
int num, n;
vector<int> ans;
void clear(int _n) {
  for (int i = int(0); i <= int((num)-1); ++i) es[i].clear();
  n = _n, num = n * 2;
}
void add_imply(int i, int j) { es[i].push_back(j); }
void add_conflicts(vector<int> is) {
  vector<int> js;
  for (int k = int(0); k <= int((static_cast<int>((is).size())) - 1); ++k)
    js.push_back(num++);
  for (int k = int(0); k <= int((static_cast<int>((is).size())) - 1); ++k) {
    es[js[k]].push_back(is[k] ^ 1);
    if (k > 0) {
      es[js[k]].push_back(js[k - 1]);
      es[is[k]].push_back(js[k - 1]);
    }
    if (k + 1 < static_cast<int>((is).size())) {
      es[js[k]].push_back(js[k + 1]);
      es[is[k]].push_back(js[k + 1]);
    }
  }
}
bool solve() {
  vector<int> belong(num, -1), low(num), dfn(num), stack;
  int counter = 0, blocks = 0;
  const function<void(int, int)> dfs = [&](int x, int fa) {
    low[x] = dfn[x] = counter++;
    stack.push_back(x);
    belong[x] = -2;
    for (int y : es[x]) {
      if (y == fa) continue;
      if (belong[y] == -1) {
        dfs(y, x);
        setmin(low[x], low[y]);
      } else if (belong[y] == -2) {
        setmin(low[x], dfn[y]);
      }
    }
    if (low[x] == dfn[x]) {
      while (1) {
        int cur = stack.back();
        stack.pop_back();
        belong[cur] = blocks;
        if (cur == x) break;
      }
      ++blocks;
    }
  };
  for (int i = int(0); i <= int((num)-1); ++i)
    if (belong[i] == -1) dfs(i, -1);
  ans.resize(n);
  for (int i = int(0); i <= int((n)-1); ++i) {
    if (belong[i * 2] == belong[i * 2 + 1]) return false;
    ans[i] = (belong[i * 2] > belong[i * 2 + 1] ? 1 : 0);
  }
  return true;
}
}  // namespace two_sat
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  struct Edge {
    int u, v, c, t, i;
  };
  vector<Edge> es(m);
  vector<unordered_map<int, vector<int>>> cs(n);
  for (int i = int(0); i <= int((m)-1); ++i) {
    scanf("%d%d%d%d", &es[i].u, &es[i].v, &es[i].c, &es[i].t);
    --es[i].u, --es[i].v;
    es[i].i = i;
    cs[es[i].u][es[i].c].push_back(i);
    cs[es[i].v][es[i].c].push_back(i);
  }
  const auto check = [&](int t) {
    two_sat::clear(m);
    for (int i = int(0); i <= int((m)-1); ++i)
      if (es[i].t > t) {
        two_sat::add_imply(i * 2 + 1, i * 2);
      }
    for (int x = int(0); x <= int((n)-1); ++x) {
      bool found = false;
      vector<int> is;
      for (const auto& kv : cs[x]) {
        if (static_cast<int>((kv.second).size()) > 2) return false;
        if (static_cast<int>((kv.second).size()) == 2) {
          if (found) return false;
          found = true;
          int i = kv.second[0], j = kv.second[1];
          two_sat::add_imply(i * 2 + 1, j * 2);
          two_sat::add_imply(j * 2 + 1, i * 2);
          two_sat::add_imply(i * 2, j * 2 + 1);
          two_sat::add_imply(j * 2, i * 2 + 1);
        } else {
          is.push_back(kv.second[0] * 2 + 1);
        }
      }
      if (found) {
        for (int i : is) {
          two_sat::add_imply(i, i ^ 1);
        }
      } else {
        two_sat::add_conflicts(is);
      }
    }
    return two_sat::solve();
  };
  int le = 0, ri = 1 << 30;
  while (le < ri) {
    int mid = (le + ri) / 2;
    if (check(mid)) {
      ri = mid;
    } else {
      le = mid + 1;
    }
  }
  if (check(le)) {
    printf("Yes\n");
    vector<int> is;
    for (int i = int(0); i <= int((m)-1); ++i)
      if (two_sat::ans[i]) is.push_back(i);
    printf("%d %d\n", le, static_cast<int>((is).size()));
    for (int i : is) printf("%d ", i + 1);
    printf("\n");
  } else {
    printf("No\n");
  }
  return 0;
}
