#include <bits/stdc++.h>
#define REP(i,n) for(int i=0;i<n;i++)
#define REPP(i,n) for(int i=1;i<=n;i++)
const double PI = acos(-1);
const double EPS = 1e-15;
long long INF=(long long)1E17;
#define i_7 (long long)(1E9+7)
long mod(long a){
    long long c=a%i_7;
    if(c>=0)return c;
    return c+i_7;
}
using namespace std;
bool prime_(int n){
  if(n==1){
    return false;
  }else if(n==2){
    return true;
  }else{
    for(int i=2;i<=sqrt(n);i++){
      if(n%i==0){
        return false;
      }
    }
    return true;
  }
}

long long gcd_(long long a, long long b){
  if(a<b){
    swap(a,b);
  }
  if(a%b==0){
    return b;
  }else{
    return gcd_(b,a%b);
  }
}
 
long long lcm_(long long x, long long y){
  return (x/gcd_(x,y))*y;
}
 
class UnionFind {
    public:
    //各頂点の親の番号を格納する。その頂点自身が親だった場合は-(その集合のサイズ)を入れる。
    vector<int> Parent;
    
    //クラスを作るときは、Parentの値を全て-1にする。
    //以下のようにすると全てバラバラの頂点として解釈できる。
    UnionFind(int N) {
        Parent = vector<int>(N, -1);
    }
    
    //Aがどのグループに属しているか調べる
    int root(int A) {
        if (Parent[A] < 0) return A;
        return Parent[A] = root(Parent[A]);
    }
    
    //自分のいるグループの頂点数を調べる
    int size(int A) {
        return -Parent[root(A)];//先祖をrootで取っておきたい。
    }
    
    //AとBをくっ付ける
    bool connect(int A, int B) {
        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
        A = root(A);
        B = root(B);
        if (A == B) {
            //すでにくっついてるからくっ付けない
            return false;
        }
        
        //大きい方(A)に小さいほう(B)をくっ付けたい
        //大小が逆だったらAとBをひっくり返す。
        if (size(A) < size(B)) swap(A, B);
        
        //Aのサイズを更新する
        Parent[A] += Parent[B];
        //Bの親をAに変更する
        Parent[B] = A;
        
        return true;
    }
};

vector<pair<int,long long>> G[100'010];
bool used[100'010];
long long pos[100'010];
long long max_pos;
long long min_pos;

void dfs(int now){
  int next_;
  long long cost;
  //bool res = true;
  for(pair<int, long long> p:G[now]){
    next_ = p.first;
    cost = p.second;
    if(used[next_]){
      continue;
    }else{
      pos[next_] = pos[now] + cost;
      used[next_] = true;
      max_pos = max(max_pos, pos[next_]);
      min_pos = min(min_pos, pos[next_]);
      dfs(next_);
    }
  }
  return;
}

bool check_(int n){
  int next_;
  long long cost;
  bool res = true;
  for(int i=0;i<n;i++){
    if(used[i]){
      for(pair<int, long long> p:G[i]){
        next_ = p.first;
        cost = p.second;
        if(pos[next_] != pos[i]+cost){
          return false;
        }else{
          continue;
        }
      }
    }else{
      continue;
    }
  }
  return true;
}

int main(){
  
  int n,m;
  cin>>n>>m;
  int l,r;
  long long d;
  REP(i,m){
    cin>>l>>r>>d;
    l--;r--;
    G[l].push_back(make_pair(r,d));
    G[r].push_back(make_pair(l,-d));
  }
  
  bool flag = true;
  bool res;
  //used[0] = true;
  max_pos = 0;
  min_pos = 0;
  REP(i,n){
    if(!used[i]){
      used[i] = true;
      pos[i] = 0;
      max_pos = min_pos = 0;
      dfs(i);
      if(max_pos-min_pos>1'000'000'000){
        cout<<"No"<<endl;
        flag = false;
        break;
      }
    }else{
      continue;
    }
  }
  
  if(flag){
    res = check_(n);
    if(res){
      cout<<"Yes"<<endl;
    }else{
      cout<<"No"<<endl;
    }
  }else{
    ;
  }
  
  return 0;
}


Measured memory_bytes: 15616