#include <bits/stdc++.h>
using namespace std;
const int n0 = 2e5 + 123;
int n, m, in[n0], T, ans[n0];
vector<array<int, 2>> g[n0];
int cur;
bool have;
vector<int> pt, comp;
void clear() {
  pt.clear(), comp.clear();
  have = 0;
}
struct Value {
  array<int, 2> t[2];
  Value(int init = 0) {
    memset(&t, 0, sizeof(t));
    if (init) t[1][1] = 1;
  }
  void upd(int c, int x) {
    if (!t[c][1]) {
      t[c][0] = x, t[c][1] = 1;
    } else {
      if (t[c][0] != x) {
        cout << "NO";
        exit(0);
      }
    }
  }
  void merge(const Value &v, int e) {
    for (int i = 0; i < 2; i++) {
      if (!v.t[i][1]) continue;
      upd(i ^ 1, e - v.t[i][0]);
    }
  }
  int get() {
    assert(t[0][1] || t[1][1]);
    if (t[0][1]) return t[0][0];
    return -t[1][0];
  }
  void check() {
    if (t[0][1] && t[1][1]) {
      int x = (t[0][0] - t[1][0]) / 2;
      if (have) {
        if (cur != x) {
          cout << "NO";
          exit(0);
        }
      } else {
        cur = x;
        have = 1;
      }
    }
  };
  int ans(int x) {
    assert(t[0][1] || t[1][1]);
    if (t[0][1]) return t[0][0] - x;
    return t[1][0] + x;
  }
} val[n0];
void dfs(int v, int p) {
  in[v] = ++T;
  for (auto &i : g[v]) {
    int to = i[0], e = i[1];
    val[to].merge(val[v], e);
    if (!in[to]) {
      dfs(to, v);
    }
  }
  val[v].check();
  pt.push_back(val[v].get());
  comp.push_back(v);
}
int main() {
  ios_base::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int x, y, z;
    cin >> x >> y >> z;
    z *= 2;
    g[x].push_back({y, z}), g[y].push_back({x, z});
  }
  for (int i = 1; i <= n; i++) {
    if (!in[i]) {
      clear();
      val[i] = Value(1);
      dfs(i, 0);
      if (!have) {
        sort(begin(pt), end(pt));
        cur = pt[(int)(pt).size() / 2];
      }
      for (int j : comp) {
        ans[j] = val[j].ans(cur);
      }
    }
  }
  cout << "YES\n";
  for (int i = 1; i <= n; i++) {
    double x = ans[i];
    x /= 2;
    cout << x << ' ';
  }
}
