#include <bits/stdc++.h>
using namespace std;
const long double epsilon = 1e-9;
vector<int> primes;
const int SIZE = (1 << 20);
bool vise[SIZE];
void deducePrimes() {
  memset(vise, false, sizeof(vise));
  for (long long i = 2; i < SIZE; i++) {
    if (!vise[i]) {
      primes.push_back((int)i);
      for (long long j = i * i; j < SIZE; j += i) vise[j] = true;
    }
  }
}
vector<int> divisors(int n1) {
  vector<int> div;
  div.push_back(1);
  for (int i = 0; i < primes.size(); i++) {
    int deg = 0;
    while (n1 % primes[i] == 0) {
      deg++;
      n1 /= primes[i];
    }
    if (deg > 0) {
      int sz = div.size();
      int temp;
      temp = primes[i];
      for (int j = 0; j < deg; j++) {
        for (int k = 0; k < sz; k++) {
          div.push_back(div[k] * temp);
        }
        temp *= primes[i];
      }
    }
  }
  return div;
}
struct rib {
  int to;
  long long gcd, lca;
};
vector<vector<rib> > neighbours;
int n;
vector<int> getReachable(int i1) {
  vector<bool> vis(n, false);
  vis[i1] = true;
  queue<int> toProcess;
  toProcess.push(i1);
  vis[i1] = true;
  int cur;
  while (!toProcess.empty()) {
    cur = toProcess.front();
    toProcess.pop();
    for (int i = 0; i < neighbours[cur].size(); i++) {
      if (!vis[neighbours[cur][i].to]) {
        vis[neighbours[cur][i].to] = true;
        toProcess.push(neighbours[cur][i].to);
      }
    }
  }
  vector<int> res;
  for (int i = 0; i < n; i++) {
    if (vis[i]) res.push_back(i);
  }
  return res;
}
long long gcd(long long a, long long b) {
  long long temp;
  if (a < b) swap(a, b);
  while (b > 0) {
    temp = a % b;
    a = b;
    b = temp;
  }
  return a;
}
int main() {
  deducePrimes();
  int m;
  cin >> n >> m;
  neighbours.resize(n);
  rib temp;
  int x, y;
  for (int i = 0; i < m; i++) {
    cin >> x >> y >> temp.gcd >> temp.lca;
    x--;
    y--;
    if (temp.lca % temp.gcd != 0) {
      cout << "NO" << endl;
      return 0;
    }
    temp.to = y;
    neighbours[x].push_back(temp);
    temp.to = x;
    neighbours[y].push_back(temp);
  }
  vector<bool> vis(n, false);
  vector<long long> res(n);
  long long x1, x2;
  for (int i1 = 0; i1 < n; i1++) {
    if (!vis[i1]) {
      if (neighbours[i1].size() == 0) {
        res[i1] = 1;
        vis[i1] = true;
        continue;
      }
      vector<int> reachable = getReachable(i1);
      vector<int> divs = divisors((int)neighbours[i1][0].lca);
      vector<bool> vis2(n, false);
      bool can2 = false;
      for (int j = 0; j < divs.size(); j++) {
        queue<int> toProcess;
        toProcess.push(i1);
        res[i1] = divs[j];
        vis2[i1] = true;
        int cur;
        bool can = true;
        while (!toProcess.empty() && can) {
          cur = toProcess.front();
          toProcess.pop();
          for (int i = 0; i < neighbours[cur].size(); i++) {
            if (!vis2[neighbours[cur][i].to]) {
              if (res[cur] % neighbours[cur][i].gcd != 0 ||
                  neighbours[cur][i].lca %
                          (res[cur] / neighbours[cur][i].gcd) !=
                      0) {
                can = false;
                break;
              }
              res[neighbours[cur][i].to] =
                  neighbours[cur][i].lca / (res[cur] / neighbours[cur][i].gcd);
              vis2[neighbours[cur][i].to] = true;
              toProcess.push(neighbours[cur][i].to);
            }
          }
        }
        if (can) {
          for (int i = 0; i < reachable.size() && can; i++) {
            for (int j1 = 0; j1 < neighbours[reachable[i]].size(); j1++) {
              x1 = gcd(res[reachable[i]], res[neighbours[reachable[i]][j1].to]);
              x2 = (res[reachable[i]] * res[neighbours[reachable[i]][j1].to]) /
                   x1;
              if (x1 != neighbours[reachable[i]][j1].gcd ||
                  x2 != neighbours[reachable[i]][j1].lca) {
                can = false;
                break;
              }
            }
          }
        }
        if (!can) {
          for (int i = 0; i < reachable.size(); i++) vis2[reachable[i]] = false;
        } else {
          can2 = true;
          for (int i = 0; i < reachable.size(); i++) vis[reachable[i]] = true;
          break;
        }
      }
      if (!can2) {
        cout << "NO" << endl;
        return 0;
      }
    }
  }
  cout << "YES" << endl;
  bool first = true;
  for (int i = 0; i < n; i++) {
    if (!first) cout << " ";
    first = false;
    cout << res[i];
  }
  cout << endl;
  return 0;
}
