#include <bits/stdc++.h>
using namespace std;
set<long long int> s_div[102];
int n, m;
vector<int> adj[102];
long long int info[102][102][2];
long long int gcd(long long int a, long long int b) {
  return !b ? a : gcd(b, a % b);
}
long long int lcm(long long int a, long long int b) {
  return (a / gcd(a, b)) * b;
}
int id[102];
bool vis[102];
stack<int> vis2;
bool f(int v, int p) {
  vis[v] = true;
  vis2.push(v);
  set<long long int>::iterator it = s_div[v].begin();
  for (; it != s_div[v].end(); ++it) {
    bool succ = true;
    id[v] = *it;
    for (int j = 0; j < adj[v].size(); ++j) {
      int v2 = adj[v][j];
      if (id[v2] != -1) {
        if (!(gcd(id[v2], *it) == info[v][v2][0] &&
              lcm(id[v2], *it) == info[v][v2][1])) {
          succ = false;
          break;
        }
      } else {
        bool res = f(adj[v][j], v);
        if (!res) {
          succ = false;
          while (!vis2.empty() && vis2.top() != v) {
            int vv = vis2.top();
            vis2.pop();
            id[vv] = -1;
          }
          break;
        }
      }
    }
    if (succ)
      return true;
    else
      while (!vis2.empty() && vis2.top() != v) {
        int vv = vis2.top();
        vis2.pop();
        id[vv] = -1;
      }
  }
  id[v] = -1;
  vis[v] = false;
  return false;
}
void intersect(set<long long int> &set_1, set<long long int> &set_2) {
  std::set<long long int>::iterator it1 = set_1.begin();
  std::set<long long int>::iterator it2 = set_2.begin();
  while ((it1 != set_1.end()) && (it2 != set_2.end())) {
    if (*it1 < *it2) {
      set_1.erase(it1++);
    } else if (*it2 < *it1) {
      ++it2;
    } else {
      ++it1;
      ++it2;
    }
  }
  set_1.erase(it1, set_1.end());
}
int main() {
  memset(id, -1, sizeof id);
  scanf("%d%d", &n, &m);
  if (m == 0) {
    printf("YES\n");
    for (int i = 0; i < n; ++i) printf("1 ");
    return 0;
  }
  for (int i = 0; i < m; ++i) {
    long long int a, b, g, l;
    scanf("%lld%lld%lld%lld", &a, &b, &g, &l);
    if (l % g != 0) {
      printf("NO\n");
      return 0;
    }
    adj[a].push_back(b);
    adj[b].push_back(a);
    info[a][b][0] = info[b][a][0] = g;
    info[a][b][1] = info[b][a][1] = l;
    vector<long long int> divs;
    for (long long int i = 1; i * i <= l; ++i) {
      if (l % i == 0) {
        divs.push_back(i);
        divs.push_back(l / i);
      }
    }
    set<long long int> poss_nums;
    set<long long int>::iterator it;
    for (long long int i = 0; i < divs.size(); ++i) {
      for (long long int j = i; j < divs.size(); ++j) {
        if (gcd(divs[i], divs[j]) == g && lcm(divs[i], divs[j]) == l) {
          poss_nums.insert(divs[i]);
          poss_nums.insert(divs[j]);
        }
      }
    }
    if (s_div[a].size() == 0)
      s_div[a].insert(poss_nums.begin(), poss_nums.end());
    else {
      intersect(s_div[a], poss_nums);
    }
    if (s_div[b].size() == 0)
      s_div[b].insert(poss_nums.begin(), poss_nums.end());
    else {
      intersect(s_div[b], poss_nums);
    }
  }
  bool son = true;
  for (int i = 1; i <= n; ++i) {
    if (!vis[i]) {
      if (s_div[i].size() == 0) {
        vis[i] = true;
        id[i] = 1;
      } else {
        bool res = f(i, -1);
        if (!res) {
          son = false;
          break;
        }
      }
    }
  }
  if (!son)
    printf("NO\n");
  else {
    printf("YES\n");
    for (int i = 1; i <= n; ++i) printf("%d ", id[i]);
  }
  return 0;
}
