Problem: You are given an undirected graph where each edge has one of two colors: black or red.

Your task is to assign a real number to each node so that: 

  * for each black edge the sum of values at its endpoints is 1; 
  * for each red edge the sum of values at its endpoints is 2; 
  * the sum of the absolute values of all assigned numbers is the smallest possible. 



Otherwise, if it is not possible, report that there is no feasible assignment of the numbers.

Input

The first line contains two integers N (1 ≤ N ≤ 100 000) and M (0 ≤ M ≤ 200 000): the number of nodes and the number of edges, respectively. The nodes are numbered by consecutive integers: 1, 2, …, N.

The next M lines describe the edges. Each line contains three integers a, b and c denoting that there is an edge between nodes a and b (1 ≤ a, b ≤ N) with color c (1 denotes black, 2 denotes red).

Output

If there is a solution, the first line should contain the word "YES" and the second line should contain N space-separated numbers. For each i (1 ≤ i ≤ N), the i-th number should be the number assigned to the node i.

Output should be such that: 

  * the sum of the numbers at the endpoints of each edge differs from the precise value by less than 10^{-6}; 
  * the sum of the absolute values of all assigned numbers differs from the smallest possible by less than 10^{-6}. 



If there are several valid solutions, output any of them.

If there is no solution, the only line should contain the word "NO".

Scoring

Subtasks: 

  1. (5 points) N ≤ 5, M ≤ 14 
  2. (12 points) N ≤ 100 
  3. (17 points) N ≤ 1000 
  4. (24 points) N ≤ 10 000 
  5. (42 points) No further constraints 

Examples

Input


4 4
1 2 1
2 3 2
1 3 2
3 4 1


Output


YES
0.5 0.5 1.5 -0.5


Input


2 1
1 2 1


Output


YES
0.3 0.7

Input


3 2
1 2 2
2 3 2


Output


YES
0 2 0


Input


3 4
1 2 2
2 2 1
2 1 1
1 2 2


Output


NO

Note

Note that in the second example the solution is not unique.

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
long long modd = 1000 * 1000 * 1000 + 7;
template <class T>
class depth_first_search_iterator {
 public:
  stack<pair<T, T>> todo;
  function<bool(T)> notvisited;
  function<void(T)> mark_visited;
  function<set<T>(T)> neighbors;
  depth_first_search_iterator() {}
  depth_first_search_iterator(T start, function<bool(T)> notv,
                              function<void(T)> mark_v,
                              function<set<T>(T)> neigh)
      : notvisited(notv),
        mark_visited(mark_v),
        neighbors(neigh),
        end_(false),
        current(start),
        prev(start) {
    todo.push(make_pair(start, start));
    operator++();
  }
  void operator++() {
    end_ = true;
    while (!todo.empty()) {
      current = todo.top().first;
      prev = todo.top().second;
      todo.pop();
      if (notvisited(current)) {
        mark_visited(current);
        for (const T x : neighbors(current)) {
          todo.push(make_pair(x, current));
        }
        end_ = false;
        break;
      }
    }
  }
  T operator*() { return current; }
  T previous() { return prev; }
  bool end() { return end_; }

 private:
  T current;
  T prev;
  bool end_;
};
template <class T>
class breadth_first_search_iterator {
 public:
  queue<pair<T, T>> todo;
  function<bool(T)> notvisited;
  function<void(T)> mark_visited;
  function<set<T>(T)> neighbors;
  breadth_first_search_iterator() {}
  breadth_first_search_iterator(T start, function<bool(T)> notv,
                                function<void(T)> mark_v,
                                function<set<T>(T)> neigh)
      : notvisited(notv),
        mark_visited(mark_v),
        neighbors(neigh),
        end_(false),
        current(start),
        prev(start) {
    todo.push(make_pair(start, start));
    operator++();
  }
  void operator++() {
    end_ = true;
    while (!todo.empty()) {
      current = todo.front().first;
      prev = todo.front().second;
      todo.pop();
      if (notvisited(current)) {
        mark_visited(current);
        for (const T x : neighbors(current)) {
          todo.push(make_pair(x, current));
        }
        end_ = false;
        break;
      }
    }
  }
  T operator*() { return current; }
  T previous() { return prev; }
  bool end() { return end_; }

 private:
  T current;
  T prev;
  bool end_;
};
template <class T>
class Graph {
 public:
  vector<T> vertices;
  vector<set<int>> neighbors;
  depth_first_search_iterator<int> dfs_iterator;
  breadth_first_search_iterator<int> bfs_iterator;
  vector<bool> visited;
  Graph() {}
  Graph(int n, T default_val = 0) {
    for (int i = 0; i < n; ++i) {
      AddVertex(default_val);
    }
  }
  void AddVertex(T val) {
    vertices.push_back(val);
    neighbors.push_back(set<int>());
  }
  bool EdgeExists(int i, int j) {
    return (neighbors[i].find(j) != neighbors[i].end());
  }
  void AddEdge(int i, int j) {
    if (!EdgeExists(i, j)) {
      neighbors[i].insert(j);
      if (i != j) {
        neighbors[j].insert(i);
      }
    }
  }
  T& operator[](int i) { return vertices[i]; }
  void RemoveEdge(int i, int j) {
    if (EdgeExists(i, j)) {
      neighbors[i].erase(find(neighbors[i].begin(), neighbors[i].end(), j));
      neighbors[j].erase(find(neighbors[j].begin(), neighbors[j].end(), i));
    }
  }
  void dfs_init(int start) {
    visited = vector<bool>(vertices.size(), false);
    dfs_iterator = depth_first_search_iterator<int>(
        start, [this](int x) { return !visited[x]; },
        [this](int x) { visited[x] = true; },
        [this](int x) { return neighbors[x]; });
  }
  void bfs_init(int start) {
    visited = vector<bool>(vertices.size(), false);
    bfs_iterator = breadth_first_search_iterator<int>(
        start, [this](int x) { return !visited[x]; },
        [this](int x) { visited[x] = true; },
        [this](int x) { return neighbors[x]; });
  }
  void print_() {
    for (int i = (0); i < (0) + (vertices.size()); ++i) {
      for (auto x : neighbors[i]) {
        if (i <= x) {
          cout << i << "-" << x << endl;
        }
      }
    }
  }
};
class UnionFind {
 public:
  vector<int> parent;
  vector<int> size;
  set<int> roots;
  UnionFind(int n) : parent(n), size(n) {
    for (int i = (0); i < (0) + (n); ++i) {
      roots.insert(i);
    }
    for (int i = (0); i < (0) + (n); ++i) {
      parent[i] = i;
      size[i] = 1;
    }
  }
  int Find(int p) {
    int root = p;
    while (root != parent[root]) {
      root = parent[root];
    }
    while (p != root) {
      int newp = parent[p];
      parent[p] = root;
      p = newp;
    }
    return root;
  }
  void Union(int p, int q) {
    int rootP = Find(p);
    int rootQ = Find(q);
    if (rootP == rootQ) {
      return;
    }
    if (size[rootP] < size[rootQ]) {
      parent[rootP] = rootQ;
      size[rootQ] += size[rootP];
      roots.erase(rootP);
    } else {
      parent[rootQ] = rootP;
      size[rootP] += size[rootQ];
      roots.erase(rootQ);
    }
  }
};
int main() {
  ios_base::sync_with_stdio(false);
  cout.precision(17);
  mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  uniform_int_distribution<int> rand_gen(0, modd);
  int test_cases = 1;
  for (int t = (1); t < (1) + (test_cases); ++t) {
    int n;
    cin >> n;
    int m;
    cin >> m;
    Graph<pair<int, int>> g(n, make_pair(0, 0));
    map<pair<int, int>, int> color;
    UnionFind components(n);
    bool problem = false;
    for (int i = (0); i < (0) + (m); ++i) {
      int aa;
      cin >> aa;
      int bb;
      cin >> bb;
      int cc;
      cin >> cc;
      if (aa != bb) {
        g.AddEdge(aa - 1, bb - 1);
      }
      if ((color.find((make_pair(aa - 1, bb - 1))) != color.end())) {
        if (color[make_pair(aa - 1, bb - 1)] != cc) {
          problem = true;
        }
      }
      if ((color.find((make_pair(bb - 1, aa - 1))) != color.end())) {
        if (color[make_pair(bb - 1, aa - 1)] != cc) {
          problem = true;
        }
      }
      color[make_pair(aa - 1, bb - 1)] = cc;
      components.Union(aa - 1, bb - 1);
    }
    if (problem) {
      cout << "NO" << endl;
      continue;
    }
    for (auto c : components.roots) {
      g[c] = make_pair(1, 0);
      g.dfs_init(c);
      ++g.dfs_iterator;
      while (!g.dfs_iterator.end()) {
        int col;
        if ((color.find(
                 (make_pair(*g.dfs_iterator, g.dfs_iterator.previous()))) !=
             color.end())) {
          col = color[make_pair(*g.dfs_iterator, g.dfs_iterator.previous())];
        } else {
          col = color[make_pair(g.dfs_iterator.previous(), *g.dfs_iterator)];
        }
        g[*g.dfs_iterator] =
            make_pair(-g[g.dfs_iterator.previous()].first,
                      col - g[g.dfs_iterator.previous()].second);
        ++g.dfs_iterator;
      }
    }
    map<int, set<pair<long long, long long>>> candidates;
    for (auto e : color) {
      pair<int, int> summ;
      summ.first = g[e.first.first].first + g[e.first.second].first;
      summ.second = g[e.first.first].second + g[e.first.second].second;
      if ((summ.first == 0) && (summ.second != e.second)) {
        problem = true;
        break;
      }
      if (summ.first != 0) {
        candidates[components.Find(e.first.first)].insert(
            make_pair(e.second - summ.second, summ.first));
      }
    }
    if (problem) {
      cout << "NO" << endl;
      continue;
    }
    map<int, map<int, int>> breakpoints;
    for (int i = (0); i < (0) + (n); ++i) {
      breakpoints[components.Find(i)][-g[i].first * g[i].second]++;
    }
    map<int, double> var;
    for (auto c : components.roots) {
      if (!candidates[c].empty()) {
        pair<long long, long long> answer = *candidates[c].begin();
        for (auto x : candidates[c]) {
          if (x.first * answer.second != x.second * answer.first) {
            problem = true;
            break;
          }
        }
        var[c] = 1.0 * answer.first / (1.0 * answer.second);
      } else {
        long long inclination = 0;
        for (auto x : breakpoints[c]) {
          inclination -= x.second;
        }
        for (auto x : breakpoints[c]) {
          long long new_inclination = inclination + 2 * x.second;
          if (inclination * new_inclination <= 0) {
            var[c] = x.first;
            break;
          }
          inclination = new_inclination;
        }
      }
    }
    if (problem) {
      cout << "NO" << endl;
      continue;
    }
    cout << "YES" << endl;
    for (int i = (0); i < (0) + (n); ++i) {
      cout << g[i].first * var[components.Find(i)] + g[i].second << " ";
    }
    cout << endl;
  }
  return 0;
}