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;
inline void proc_status() {
  ifstream t("/proc/self/status");
  cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>())
       << endl;
}
template <typename T>
inline int chkmin(T &a, const T &b) {
  return b < a ? a = b, 1 : 0;
}
template <typename T>
inline int chkmax(T &a, const T &b) {
  return b > a ? a = b, 1 : 0;
}
template <typename T>
inline T sqr(const T &val) {
  return val * val;
}
namespace fastIO {
const int MAX_BUFFER_SIZE = 1 << 16;
char buffer[MAX_BUFFER_SIZE], *cur = buffer, *ed = buffer;
inline char getc() {
  return *(cur == ed ? ed = buffer + fread(buffer, 1, MAX_BUFFER_SIZE, stdin),
           cur = buffer : cur)++;
}
}  // namespace fastIO
using fastIO::getc;
template <typename T>
inline T read() {
  register T sum(0), fg(1);
  register char ch(getc());
  for (; !isdigit(ch); ch = getc())
    if (ch == '-') fg = -1;
  for (; isdigit(ch); ch = getc()) sum = sum * 10 - '0' + ch;
  return sum * fg;
}
const int MAXN = (int)5e4;
struct edge {
  int u, v, c, w;
  edge() {}
  edge(int _u, int _v, int _c, int _w) : u(_u), v(_v), c(_c), w(_w) {}
};
int n, m;
edge E[MAXN + 5];
inline void input() {
  n = read<int>(), m = read<int>();
  for (int i = 1; i <= m; ++i)
    E[i].u = read<int>(), E[i].v = read<int>(), E[i].c = read<int>(),
    E[i].w = read<int>();
}
unordered_map<int, vector<int> > ids[MAXN + 5];
vector<int> all[MAXN + 5];
int uid[MAXN + 5], vid[MAXN + 5];
int auid[MAXN + 5], avid[MAXN + 5];
int cnt;
namespace SAT {
const int MAX_NODE = MAXN * 20;
int N, X[MAXN + 5], Y[MAXN + 5];
vector<int> adj[MAX_NODE + 5];
inline void add_edge(int u, int v) { adj[u].push_back(v); }
int dfn[MAX_NODE + 5], low[MAX_NODE + 5], dfn_cur;
int sid[MAX_NODE + 5], scnt;
inline void build(int _N) {
  for (int i = 1; i <= cnt; ++i) dfn[i] = low[i] = sid[i] = 0, adj[i].clear();
  N = _N, cnt = 0;
  for (int i = 1; i <= N; ++i) X[i] = ++cnt, Y[i] = ++cnt;
}
vector<int> stk;
inline void dfs(int u, int fa) {
  dfn[u] = low[u] = ++dfn_cur;
  stk.push_back(u);
  for (auto v : adj[u])
    if (v != fa) {
      if (!dfn[v]) {
        dfs(v, u);
        chkmin(low[u], low[v]);
      } else if (!sid[v])
        chkmin(low[u], dfn[v]);
    }
  if (low[u] == dfn[u]) {
    ++scnt;
    while (!stk.empty()) {
      int p = stk.back();
      stk.pop_back();
      sid[p] = scnt;
      if (p == u) break;
    }
  }
}
inline int solve() {
  dfn_cur = scnt = 0;
  stk.clear();
  for (int i = 1; i <= N; ++i) {
    if (!dfn[X[i]]) dfs(X[i], 0);
    if (!dfn[Y[i]]) dfs(Y[i], 0);
  }
  for (int i = 1; i <= N; ++i)
    if (sid[X[i]] == sid[Y[i]]) return 0;
  return 1;
}
}  // namespace SAT
inline int check(int LIM) {
  using SAT::X;
  using SAT::Y;
  static unordered_map<int, vector<int> > preX[MAXN + 5], preY[MAXN + 5],
      sufX[MAXN + 5], sufY[MAXN + 5];
  static vector<int> preaX[MAXN + 5], preaY[MAXN + 5], sufaX[MAXN + 5],
      sufaY[MAXN + 5];
  SAT::build(m);
  for (int i = 1; i <= n; ++i) {
    for (const auto &it : ids[i]) {
      const vector<int> &id = it.second;
      vector<int> &preX0 = preX[i][it.first];
      vector<int> &preY0 = preY[i][it.first];
      preX0.resize(((int)(it.second).size()));
      preY0.resize(((int)(it.second).size()));
      for (int j = 0; j < ((int)(id).size()); ++j) {
        preX0[j] = ++cnt;
        SAT::add_edge(preX0[j], X[id[j]]);
        if (j > 0) SAT::add_edge(preX0[j], preX0[j - 1]);
        preY0[j] = ++cnt;
        SAT::add_edge(preY0[j], Y[id[j]]);
        if (j > 0) SAT::add_edge(preY0[j], preY0[j - 1]);
      }
      vector<int> &sufX0 = sufX[i][it.first];
      vector<int> &sufY0 = sufY[i][it.first];
      sufX0.resize(((int)(it.second).size()));
      sufY0.resize(((int)(it.second).size()));
      for (int j = ((int)(id).size()) - 1; j >= 0; --j) {
        sufX0[j] = ++cnt;
        SAT::add_edge(sufX0[j], X[id[j]]);
        if (j + 1 < ((int)(id).size())) SAT::add_edge(sufX0[j], sufX0[j + 1]);
        sufY0[j] = ++cnt;
        SAT::add_edge(sufY0[j], Y[id[j]]);
        if (j + 1 < ((int)(id).size())) SAT::add_edge(sufY0[j], sufY0[j + 1]);
      }
    }
    preaX[i].resize(((int)(all[i]).size()));
    preaY[i].resize(((int)(all[i]).size()));
    for (int j = 0; j < ((int)(all[i]).size()); ++j) {
      preaX[i][j] = ++cnt;
      SAT::add_edge(preaX[i][j], X[all[i][j]]);
      if (j > 0) SAT::add_edge(preaX[i][j], preaX[i][j - 1]);
      preaY[i][j] = ++cnt;
      SAT::add_edge(preaY[i][j], Y[all[i][j]]);
      if (j > 0) SAT::add_edge(preaY[i][j], preaY[i][j - 1]);
    }
    sufaX[i].resize(((int)(all[i]).size()));
    sufaY[i].resize(((int)(all[i]).size()));
    for (int j = ((int)(all[i]).size()) - 1; j >= 0; --j) {
      sufaX[i][j] = ++cnt;
      SAT::add_edge(sufaX[i][j], X[all[i][j]]);
      if (j + 1 < ((int)(all[i]).size()))
        SAT::add_edge(sufaX[i][j], sufaX[i][j + 1]);
      sufaY[i][j] = ++cnt;
      SAT::add_edge(sufaY[i][j], Y[all[i][j]]);
      if (j + 1 < ((int)(all[i]).size()))
        SAT::add_edge(sufaY[i][j], sufaY[i][j + 1]);
    }
  }
  auto add_lim = [&](int i, int p, int p0, int u) {
    int c0 = E[i].c;
    const vector<int> &id = ids[u][c0];
    const vector<int> &preX0 = preX[u][c0];
    const vector<int> &preY0 = preY[u][c0];
    const vector<int> &sufX0 = sufX[u][c0];
    const vector<int> &sufY0 = sufY[u][c0];
    if (p > 0) {
      SAT::add_edge(Y[i], preX0[p - 1]);
      SAT::add_edge(preY0[p - 1], X[i]);
    }
    if (p + 1 < ((int)(id).size())) {
      SAT::add_edge(Y[i], sufX0[p + 1]);
      SAT::add_edge(sufY0[p + 1], X[i]);
    }
    if (p0 > 0) {
      SAT::add_edge(X[i], preaY[u][p0 - 1]);
      SAT::add_edge(preaX[u][p0 - 1], Y[i]);
    }
    if (p0 + 1 < ((int)(all[u]).size())) {
      SAT::add_edge(X[i], sufaY[u][p0 + 1]);
      SAT::add_edge(sufaX[u][p0 + 1], Y[i]);
    }
  };
  for (int i = 1; i <= m; ++i) {
    if (E[i].w > LIM) SAT::add_edge(X[i], Y[i]);
    add_lim(i, uid[i], auid[i], E[i].u);
    add_lim(i, vid[i], avid[i], E[i].v);
  }
  return SAT::solve();
}
inline void output(int LIM) {
  printf("%d ", LIM);
  using SAT::X;
  using SAT::Y;
  static unordered_map<int, vector<int> > preX[MAXN + 5], preY[MAXN + 5],
      sufX[MAXN + 5], sufY[MAXN + 5];
  static vector<int> preaX[MAXN + 5], preaY[MAXN + 5], sufaX[MAXN + 5],
      sufaY[MAXN + 5];
  SAT::build(m);
  for (int i = 1; i <= n; ++i) {
    for (const auto &it : ids[i]) {
      const vector<int> &id = it.second;
      vector<int> &preX0 = preX[i][it.first];
      vector<int> &preY0 = preY[i][it.first];
      preX0.resize(((int)(it.second).size()));
      preY0.resize(((int)(it.second).size()));
      for (int j = 0; j < ((int)(id).size()); ++j) {
        preX0[j] = ++cnt;
        SAT::add_edge(preX0[j], X[id[j]]);
        if (j > 0) SAT::add_edge(preX0[j], preX0[j - 1]);
        preY0[j] = ++cnt;
        SAT::add_edge(preY0[j], Y[id[j]]);
        if (j > 0) SAT::add_edge(preY0[j], preY0[j - 1]);
      }
      vector<int> &sufX0 = sufX[i][it.first];
      vector<int> &sufY0 = sufY[i][it.first];
      sufX0.resize(((int)(it.second).size()));
      sufY0.resize(((int)(it.second).size()));
      for (int j = ((int)(id).size()) - 1; j >= 0; --j) {
        sufX0[j] = ++cnt;
        SAT::add_edge(sufX0[j], X[id[j]]);
        if (j + 1 < ((int)(id).size())) SAT::add_edge(sufX0[j], sufX0[j + 1]);
        sufY0[j] = ++cnt;
        SAT::add_edge(sufY0[j], Y[id[j]]);
        if (j + 1 < ((int)(id).size())) SAT::add_edge(sufY0[j], sufY0[j + 1]);
      }
    }
    preaX[i].resize(((int)(all[i]).size()));
    preaY[i].resize(((int)(all[i]).size()));
    for (int j = 0; j < ((int)(all[i]).size()); ++j) {
      preaX[i][j] = ++cnt;
      SAT::add_edge(preaX[i][j], X[all[i][j]]);
      if (j > 0) SAT::add_edge(preaX[i][j], preaX[i][j - 1]);
      preaY[i][j] = ++cnt;
      SAT::add_edge(preaY[i][j], Y[all[i][j]]);
      if (j > 0) SAT::add_edge(preaY[i][j], preaY[i][j - 1]);
    }
    sufaX[i].resize(((int)(all[i]).size()));
    sufaY[i].resize(((int)(all[i]).size()));
    for (int j = ((int)(all[i]).size()) - 1; j >= 0; --j) {
      sufaX[i][j] = ++cnt;
      SAT::add_edge(sufaX[i][j], X[all[i][j]]);
      if (j + 1 < ((int)(all[i]).size()))
        SAT::add_edge(sufaX[i][j], sufaX[i][j + 1]);
      sufaY[i][j] = ++cnt;
      SAT::add_edge(sufaY[i][j], Y[all[i][j]]);
      if (j + 1 < ((int)(all[i]).size()))
        SAT::add_edge(sufaY[i][j], sufaY[i][j + 1]);
    }
  }
  auto add_lim = [&](int i, int p, int p0, int u) {
    int c0 = E[i].c;
    const vector<int> &id = ids[u][c0];
    const vector<int> &preX0 = preX[u][c0];
    const vector<int> &preY0 = preY[u][c0];
    const vector<int> &sufX0 = sufX[u][c0];
    const vector<int> &sufY0 = sufY[u][c0];
    if (p > 0) {
      SAT::add_edge(Y[i], preX0[p - 1]);
      SAT::add_edge(preY0[p - 1], X[i]);
    }
    if (p + 1 < ((int)(id).size())) {
      SAT::add_edge(Y[i], sufX0[p + 1]);
      SAT::add_edge(sufY0[p + 1], X[i]);
    }
    if (p0 > 0) {
      SAT::add_edge(X[i], preaY[u][p0 - 1]);
      SAT::add_edge(preaX[u][p0 - 1], Y[i]);
    }
    if (p0 + 1 < ((int)(all[u]).size())) {
      SAT::add_edge(X[i], sufaY[u][p0 + 1]);
      SAT::add_edge(sufaX[u][p0 + 1], Y[i]);
    }
  };
  for (int i = 1; i <= m; ++i) {
    if (E[i].w > LIM) SAT::add_edge(X[i], Y[i]);
    add_lim(i, uid[i], auid[i], E[i].u);
    add_lim(i, vid[i], avid[i], E[i].v);
  }
  SAT::solve();
  vector<int> ans;
  for (int i = 1; i <= m; ++i)
    if (SAT::sid[X[i]] < SAT::sid[Y[i]]) ans.push_back(i);
  printf("%d\n", ((int)(ans).size()));
  for (auto i : ans) printf("%d ", i);
  puts("");
}
inline void solve() {
  for (int i = 1; i <= m; ++i) {
    ids[E[i].u][E[i].c].push_back(i);
    ids[E[i].v][E[i].c].push_back(i);
    all[E[i].u].push_back(i);
    all[E[i].v].push_back(i);
  }
  for (int i = 1; i <= n; ++i) {
    for (auto &it : ids[i])
      sort((it.second).begin(), (it.second).end()),
          it.second.erase(unique((it.second).begin(), (it.second).end()),
                          it.second.end());
    sort((all[i]).begin(), (all[i]).end()),
        all[i].erase(unique((all[i]).begin(), (all[i]).end()), all[i].end());
  }
  for (int i = 1; i <= m; ++i) {
    uid[i] = lower_bound((ids[E[i].u][E[i].c]).begin(),
                         (ids[E[i].u][E[i].c]).end(), i) -
             ids[E[i].u][E[i].c].begin();
    vid[i] = lower_bound((ids[E[i].v][E[i].c]).begin(),
                         (ids[E[i].v][E[i].c]).end(), i) -
             ids[E[i].v][E[i].c].begin();
    auid[i] = lower_bound((all[E[i].u]).begin(), (all[E[i].u]).end(), i) -
              all[E[i].u].begin();
    avid[i] = lower_bound((all[E[i].v]).begin(), (all[E[i].v]).end(), i) -
              all[E[i].v].begin();
  }
  if (!check((int)1e9)) {
    puts("No");
    return;
  }
  int l = 0, r = (int)1e9;
  while (l < r) {
    int mid = (l + r) / 2;
    if (check(mid))
      r = mid;
    else
      l = mid + 1;
  }
  puts("Yes");
  output(r);
}
int main() {
  input();
  solve();
  return 0;
}
