#include <bits/stdc++.h>
using namespace std;
struct E {
  int v, u, c, t, n;
  E() { v = u = c = t = n = 0; }
  E(int _v, int _u, int _c, int _t, int _n) {
    v = _v;
    u = _u;
    c = _c;
    t = _t;
    n = _n;
  }
};
int n, m;
int comp[2 * 65536];
bool other[65536];
bool seen[2 * 65536];
bool full[65536];
bool ans[65536];
E edges[65536];
map<int, uint32_t> edj[65536];
vector<int> vertees[65536];
vector<int> adj[2 * 65536];
vector<int> adjt[2 * 65536];
vector<int> order;
set<int> ince[65536];
inline void impossible() {
  puts("No");
  exit(0);
}
inline void add_edge(const E &e) {
  if (edj[e.v][e.c]) {
    if (edj[e.v][e.c] > 65536 || full[e.v]) impossible();
    adj[e.n ^ 65536].push_back(edj[e.v][e.c]);
    adj[edj[e.v][e.c] ^ 65536].push_back(e.n);
    adjt[edj[e.v][e.c]].push_back(e.n ^ 65536);
    adjt[e.n].push_back(edj[e.v][e.c] ^ 65536);
    edj[e.v][e.c] |= e.n << 16;
    full[e.v] = true;
  } else {
    edj[e.v][e.c] |= e.n;
  }
  vertees[e.v].push_back(e.n);
}
inline void fill_inces() {
  for (int i = 1; i <= n; i++) {
    for (auto x : vertees[i]) {
      ince[i].insert(x);
    }
  }
}
inline int get(int v) {
  if (v > 65536) return INT32_MAX;
  for (auto x : ince[edges[v].u]) {
    if (x != v) return x;
  }
  for (auto x : ince[edges[v].v]) {
    if (x != v) return x;
  }
  return INT32_MAX;
}
inline void rem(int v) {
  ince[edges[v].u].erase(v);
  ince[edges[v].v].erase(v);
}
void dfs1(int v) {
  seen[v] = true;
  if (v > 65536) rem(v ^ 65536);
  for (auto x : adj[v]) {
    if (!seen[x]) dfs1(x);
  }
  if (v < 65536 && other[v]) {
    if (!seen[v ^ 65536]) {
      dfs1(v ^ 65536);
    }
  }
  while (true) {
    int x = get(v);
    if (x == INT32_MAX) break;
    dfs1(x ^ 65536);
  }
  order.push_back(v);
}
void dfs2(int v, int cn) {
  comp[v] = cn;
  if (v < 65536) {
    rem(v);
  }
  for (auto x : adjt[v]) {
    if (!comp[x]) {
      dfs2(x, cn);
    }
  }
  if (v > 65536 && other[v ^ 65536]) {
    if (!comp[v ^ 65536]) {
      dfs2(v ^ 65536, cn);
    }
  }
  while (true) {
    int x = get(v ^ 65536);
    if (x == INT32_MAX) break;
    dfs2(x, cn);
  }
}
bool s2sat(int mxt) {
  order.clear();
  fill(seen, seen + (2 * 65536), false);
  fill(comp, comp + (2 * 65536), 0);
  fill_inces();
  for (int i = 1; i <= m; i++) {
    other[i] = edges[i].t > mxt;
  }
  for (int i = 1, v = 1; i <= (m << 1);
       i++, v = (i & 1) ? ((i + 1) >> 1) : ((i >> 1) ^ 65536)) {
    if (!seen[v]) dfs1(v);
  }
  fill_inces();
  int cnum = 1;
  while (order.size()) {
    int v = order.back();
    order.pop_back();
    if (!comp[v]) dfs2(v, cnum++);
  }
  for (int i = 1; i <= m; i++) {
    if (comp[i] == comp[i ^ 65536]) return false;
    ans[i] = comp[i] > comp[i ^ 65536];
  }
  return true;
}
int main() {
  scanf("%d%d", &n, &m);
  for (uint32_t i = 1; i <= m; i++) {
    E e;
    scanf("%d%d%d%d", &e.v, &e.u, &e.c, &e.t);
    e.n = i;
    edges[i] = e;
    add_edge(e);
    swap(e.v, e.u);
    add_edge(e);
  }
  int l = 0;
  int r = INT32_MAX >> 1;
  if (!s2sat(r)) {
    impossible();
  }
  puts("Yes");
  while (l < r) {
    int mid = (l + r) >> 1;
    if (s2sat(mid))
      r = mid;
    else
      l = mid + 1;
  }
  s2sat(l);
  vector<int> anss;
  for (int i = 1; i <= m; i++) {
    if (ans[i]) anss.push_back(i);
  }
  printf("%d %d\n", l, anss.size());
  for (auto x : anss) printf("%d ", x);
  puts("");
}
