#include <bits/stdc++.h>
using namespace std;
template <typename T, typename U>
inline void amin(T &x, U y) {
  if (y < x) x = y;
}
template <typename T, typename U>
inline void amax(T &x, U y) {
  if (x < y) x = y;
}
long long int MOD = 1000000007;
int N, M;
vector<pair<pair<int, long long>, bool> > hen[100005];
struct UnionFind {
  vector<int> data;
  void init(int n) { data.assign(n, -1); }
  bool unionSet(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[y] < data[x]) swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
    return x != y;
  }
  bool findSet(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  int size(int x) { return -data[root(x)]; }
};
bool used[100005];
long long xza[100005];
bool checked[100005];
bool ans;
void dfs(int i) {
  for (int j = 0; j < hen[i].size(); j++) {
    bool hoge = hen[i][j].second;
    pair<int, long long> fuga = hen[i][j].first;
    int to = fuga.first;
    long long d = fuga.second;
    if (hoge == true) {
      if (used[to] == false) {
        used[to] = true;
        xza[to] = xza[i] + d;
      } else {
        if (xza[to] - xza[i] != d) ans = false;
      }
      hen[i][j].second = false;
      dfs(to);
    }
  }
}
int main() {
  cin >> N >> M;
  ans = true;
  for (int(i) = 0; (i) < (int)(100005); ++(i)) used[i] = false, xza[i] = 0;
  UnionFind uf;
  uf.init(N);
  for (int i = 0; i < M; i++) {
    int l, r;
    long long d;
    cin >> l >> r >> d;
    l--;
    r--;
    uf.unionSet(l, r);
    hen[l].push_back(make_pair((make_pair((r), (d))), (true)));
    hen[r].push_back(make_pair((make_pair((l), (-d))), (true)));
  }
  vector<int> rts;
  for (int i = 0; i < N; i++) {
    if (uf.root(i) == i) rts.push_back(i);
  }
  for (int i = 0; i < rts.size(); i++) {
    int ne = rts[i];
    xza[ne] = (long long)0;
    used[ne] = true;
    dfs(ne);
  }
  if (ans) {
    cout << "Yes" << endl;
  } else {
    cout << "No" << endl;
  }
}
