// Slower C++ solution:
#include <bits/stdc++.h>



using namespace std;

typedef long long ll;



struct edge {

  int to, cost;

  edge() {}

  edge(int t, int c) : to(t), cost(c) {}

};



int n, m;

vector<edge> g[100010];

vector<int> d(100010);

vector<bool> used(100010);



bool dfs(int v) {

  bool res = true;

  for (auto &e : g[v]) {

    if (used[e.to]) {

      if (d[e.to] == d[v] + e.cost) continue;

      return false;

    }

    used[e.to] = true;

    d[e.to] = d[v] + e.cost;

    res &= dfs(e.to);

  }

  return res;

}



int main() {

  cin.tie(0);

  ios_base::sync_with_stdio(false);

  

  cin >> n >> m;

  for (int i = 0; i < m; i++) {

    int l, r, d;

    cin >> l >> r >> d;

    l--, r--;

    g[l].push_back(edge(r, d));

    g[r].push_back(edge(l, -d));

  }



  for (int i = 0; i < n; i++) {

    if (used[i]) continue;

    used[i] = true;

    d[i] = 0;

    if (!dfs(i)) {

      cout << "No\n";

      return 0;

    }

  }

  cout << "Yes\n";



  return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.8982075206864972x):
#include <bits/stdc++.h>

#define int long long

#define pii pair<int,int>

#define FOR(i,a,b) for(int i=(a);i<(b);++i)

#define REP(i,n) FOR(i,0,n)

#define ALL(c) (c).begin(),(c).end()

#define ZERO(a) memset(a,0,sizeof(a))

#define MINUS(a) memset(a,0xff,sizeof(a))

#define MINF(a) memset(a,0x3f,sizeof(a))

#define POW(n) (1LL<<(n))

#define IN(i,a,b) (a <= i && i <= b)

using namespace std;

template <typename T> inline bool CHMIN(T& a,T b) { if(a>b) { a=b; return 1; } return 0; }

template <typename T> inline bool CHMAX(T& a,T b) { if(a<b) { a=b; return 1; } return 0; }

template <typename T> inline void SORT(T& a) { sort(ALL(a)); }

template <typename T> inline void REV(T& a) { reverse(ALL(a)); }

template <typename T> inline void UNI(T& a) { sort(ALL(a)); a.erase(unique(ALL(a)),a.end()); }

const int MOD = 1000000007;

const int INF = 0x3f3f3f3f3f3f3f3f;

const double EPS = 1e-10;

/* ---------------------------------------------------------------------------------------------------- */



template <typename T>

struct WUF {

  int n, c;

  vector<int> p;

  vector<T> dw;

  WUF() {}

  WUF(int n) : n(n), c(n), p(n, -1), dw(n) {}

  int find(int x) {

    if (p[x] < 0) return x;

    int r = find(p[x]);

    dw[x] += dw[p[x]];

    return p[x] = r;

  }

  // x から見た y の重みを w に設定する

  int unite(int x, int y, T w) {

    w += weight(x); w -= weight(y);

    x = find(x); y = find(y);

    if (x == y) return w == 0;

    if (p[x] > p[y]) swap(x,y), w = -w;

    p[x] += p[y];

    p[y] = x;

    dw[y] = w;

    c--;

    return 1;

  }

  // 根から見た x の重み

  T weight(int x) {

    find(x);

    return dw[x];

  }

  // x から見た y の重み

  T diff(int x, int y) {

    assert(same(x, y));

    return weight(y) - weight(x);

  }

  bool same(int x, int y) {

    return find(x) == find(y);

  }

  // x を含む集合のサイズ

  int size(int x) {

    return -p[find(x)];

  }

  // 連結成分の個数

  int count() {

    return c;

  }

};



signed main() {

  cin.tie(0);

  ios_base::sync_with_stdio(false);

  cout << fixed << setprecision(10);



  int N,M;

  cin >> N >> M;

  WUF<int> wuf(N);

  bool yes = true;

  REP(i,M) {

    int L,R,D;

    cin >> L >> R >> D;

    L--; R--;

    yes &= wuf.unite(L,R,D);

  }

  cout << (yes ? "Yes" : "No") << endl;



  return 0;

}