void main(){
  import std.stdio, std.string, std.conv, std.algorithm;
  import std.typecons;

  int n, m; rd(n, m);
  auto l=new int[](m), r=new int[](m), d=new int[](m);
  foreach(i; 0..m){
    rd(l[i], r[i], d[i]);
    l[i]--; r[i]--;
  }

  alias T=Tuple!(int, "to", long, "d");
  auto g=new T[][](n), rev=new T[][](n);
  foreach(i; 0..m){
    g[l[i]]~=T(r[i], d[i]);
    rev[r[i]]~=T(l[i], d[i]);
  }
  auto a=new long[](n), vis=new bool[](n);
  long dmin=0, dmax=0;
  bool fun(int cur, int pre=-1, long p=0){
    // writeln(cur);
    if(vis[cur]){
      if(a[cur]!=p) return false;
      else return true;
    }else{
      vis[cur]=true;
      a[cur]=p;
      dmin=min(dmin, p);
      dmax=max(dmax, p);
    }
    bool ret=true;
    foreach(e; g[cur]){
      if(e.to==pre) continue;
      ret&=fun(e.to, cur, p+e.d);
    }
    foreach(e; rev[cur]){
      if(e.to==pre) continue;
      ret&=fun(e.to, cur, p-e.d);
    }
    return ret;
  }
  foreach(i; 0..n)if(vis[i]==false){
    // writeln(i);
    dmin=dmax=0;
    if(fun(i)==false){writeln("No"); return;}
    if(dmax-dmin>1_000_000_000){writeln("No"); return;}
  }

  writeln("Yes");
}

void rd(T...)(ref T x){
  import std.stdio, std.string, std.conv;
  auto l=readln.split;
  assert(l.length==x.length);
  foreach(i, ref e; x){
    e=l[i].to!(typeof(e));
  }
}
void wr(T...)(T x){
  import std.stdio;
  foreach(e; x) write(e, " ");
  writeln();
}