#include <bits/stdc++.h>
using namespace std;
int V;
vector<int> G[400100];
vector<int> rG[400100];
vector<int> vs;
bool used[400100];
int cmp[400100];
void clear_graph() {
  for (int i = 0; i < 400100; i++) {
    G[i].clear();
    rG[i].clear();
  }
  vs.clear();
}
void add_edge(int from, int to) {
  G[from].push_back(to);
  rG[to].push_back(from);
}
void dfs(int v) {
  used[v] = true;
  for (int i = 0; i < G[v].size(); i++) {
    if (!used[G[v][i]]) dfs(G[v][i]);
  }
  vs.push_back(v);
}
void rdfs(int v, int k) {
  used[v] = true;
  cmp[v] = k;
  for (int i = 0; i < rG[v].size(); i++) {
    if (!used[rG[v][i]]) rdfs(rG[v][i], k);
  }
}
void scc() {
  memset(cmp, -1, sizeof(cmp));
  memset(used, false, sizeof(used));
  for (int i = 0; i < V; i++)
    if (!used[i]) dfs(i);
  int k = 0;
  memset(used, false, sizeof(used));
  for (int i = (int)vs.size() - 1; i >= 0; i--) {
    if (!used[vs[i]]) rdfs(vs[i], k++);
  }
}
int n, m;
vector<int> adj[50010];
int col[50010];
int t[50010];
map<int, int> cnt;
map<int, int> cnt2[50010];
vector<int> use[50010];
int must[50010];
int ind;
bool make_graph(int limit) {
  memset(must, -1, sizeof(must));
  for (int i = 0; i < n; i++) use[i].clear();
  for (int i = 0; i < n; i++) cnt2[i].clear();
  for (int i = 0; i < n; i++) {
    int c = 0;
    cnt.clear();
    map<int, int>::iterator it;
    for (int j = 0; j < adj[i].size(); j++) {
      int id = adj[i][j];
      if (t[id] <= limit) {
        cnt[col[id]]++;
        use[i].push_back(id);
      } else {
        if (cnt2[i].find(col[id]) != cnt2[i].end()) return false;
        cnt2[i][col[id]] = id;
      }
    }
    for (it = cnt.begin(); it != cnt.end(); it++) {
      if ((it->second) > 2) return false;
      if ((it->second) == 2) {
        c++;
        must[i] = it->first;
      }
    }
    if (c > 1) return false;
  }
  ind = 2 * m;
  clear_graph();
  for (int i = 0; i < n; i++) {
    int num = (int)use[i].size();
    int m1 = -1, m2 = -1;
    for (int j = 0; j < num; j++) {
      add_edge(ind + j, use[i][j] + m);
      if (j < num - 1) add_edge(ind + j, ind + j + 1);
      add_edge(ind + num + j, use[i][j] + m);
      if (j > 0) add_edge(ind + num + j, ind + num + j - 1);
      if (j < num - 1) add_edge(use[i][j], ind + j + 1);
      if (j > 0) add_edge(use[i][j], ind + num + j - 1);
      if (col[use[i][j]] == must[i]) {
        if (m1 == -1)
          m1 = use[i][j];
        else
          m2 = use[i][j];
      }
      map<int, int>::iterator it;
      if ((it = cnt2[i].find(col[use[i][j]])) != cnt2[i].end())
        add_edge(use[i][j] + m, use[i][j]);
    }
    if (m1 != -1 && m2 != -1) {
      add_edge(m1 + m, m2);
      add_edge(m2 + m, m1);
    }
    ind += 2 * num;
  }
  V = ind;
  return true;
}
vector<int> ans;
bool check(int limit, bool recover) {
  if (!make_graph(limit)) return false;
  scc();
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < use[i].size(); j++) {
      int id = use[i][j];
      if (cmp[id] == cmp[id + m]) return false;
      if (recover && cmp[id] > cmp[id + m]) ans.push_back(id + 1);
    }
  }
  return true;
}
int main() {
  scanf("%d %d", &n, &m);
  for (int i = 0; i < m; i++) {
    int u, v;
    scanf("%d %d %d %d", &u, &v, &col[i], &t[i]);
    u--;
    v--;
    adj[u].push_back(i);
    adj[v].push_back(i);
  }
  int l = -1, r = 1000000100;
  while (r - l > 1) {
    int mid = (l + r) / 2;
    if (check(mid, false))
      r = mid;
    else
      l = mid;
  }
  if (r == 1000000100)
    printf("No\n");
  else {
    printf("Yes\n");
    check(r, true);
    sort((ans).begin(), (ans).end());
    ans.erase(unique((ans).begin(), (ans).end()), ans.end());
    int k = (int)ans.size();
    printf("%d %d\n", r, k);
    for (int i = 0; i < k; i++)
      printf("%d%c", ans[i], (i == k - 1) ? '\n' : ' ');
  }
  return 0;
}
