// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

 

#define REP(i, s) for (int i = 0; i < s; ++i)

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

#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl

#define EACH(i, s) for (__typeof__((s).begin()) i = (s).begin(); i != (s).end(); ++i)

#define DEBUG

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

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

template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)

{ return s << '<' << P.first << ", " << P.second << '>'; }

template<class T> ostream& operator << (ostream &s, vector<T> P)

{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }

template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)

{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }

template<class T> ostream& operator << (ostream &s, set<T> P)

{ EACH(it, P) { s << "<" << *it << "> "; } return s << endl; }

template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)

{ EACH(it, P) { s << "<" << it->first << "->" << it->second << "> "; } return s << endl; }

template<class T>void show(vector<T>v){for (int i = 0; i < v.size(); i++){cerr<<v[i]<<" ";}cerr<<"\n";}

typedef long long ll;

#define INF 1e6

#define int long long

struct UnionFind

{

    vector<int> par;

   

    UnionFind(int n) : par(n,-1){}

    void init(int n) { par.assign(n,-1);}

 

    int root(int x){

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

        return par[x]=root(par[x]);

    }

 

    bool issame(int x, int y){

        return root(x)==root(y);

    }

    bool merge(int x, int y){

        x=root(x);

        y=root(y);

        if(x==y) return false;

        if(par[x]>par[y])swap(x,y);

        par[x]+=par[y];

        par[y]=x; //大きさが正になるよ

        return true;

    }

    int size(int x){

        return -par[root(x)];

    }

};

ll x[100010];



int V[100010],X[100010];

vector<vector<pair<int,int>>>v(100000);

bool judge=true;

void dfs(long long n){

    V[n]=1;

    for (int i = 0; i < v[n].size(); i++)

    {

        if(X[v[n][i].first]==INF){

            X[v[n][i].first]=X[n]+v[n][i].second;

        }

        else if(X[v[n][i].first]!=X[n]+v[n][i].second) judge=false;

        if(V[v[n][i].first]==0)dfs(v[n][i].first);

     }

    

}

void dfs1(int n){

	V[n] = 1;

	for(int i=0;i<v[n].size();i++){

		if(X[v[n][i].first] == INF) X[v[n][i].first] = X[n] + v[n][i].second;

		else if(X[v[n][i].first] != X[n] + v[n][i].second) judge = false;

		if(V[v[n][i].first] == 0) dfs(v[n][i].first);

	}

}

int l[200010],r[200010],d[200010];

signed main(){

    int n,m;

    cin>>n>>m;

    

    

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

    {

        X[i]=INF;

    }

    

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

    {

        cin>>l[i]>>r[i]>>d[i];

        l[i]--;

        r[i]--;



    }

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

   {

        v[l[i]].push_back(make_pair(r[i],-d[i]));

        v[r[i]].push_back(make_pair(l[i],d[i]));

   }

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

   {

    if(V[i]==0){

        X[i]=0;

        dfs1(i);

        }   

   }

   if(judge) cout<<"Yes"<<endl;

   else cout<<"No"<<endl;

   

    

    

   



    return 0;

}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;

 

#define REP(i, s) for (int i = 0; i < s; ++i)

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

#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl

#define EACH(i, s) for (__typeof__((s).begin()) i = (s).begin(); i != (s).end(); ++i)

#define DEBUG

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

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

template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)

{ return s << '<' << P.first << ", " << P.second << '>'; }

template<class T> ostream& operator << (ostream &s, vector<T> P)

{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }

template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)

{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }

template<class T> ostream& operator << (ostream &s, set<T> P)

{ EACH(it, P) { s << "<" << *it << "> "; } return s << endl; }

template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)

{ EACH(it, P) { s << "<" << it->first << "->" << it->second << "> "; } return s << endl; }

template<class T>void show(vector<T>v){for (int i = 0; i < v.size(); i++){cerr<<v[i]<<" ";}cerr<<"\n";}

typedef long long ll;

#define INF 1e6





template<class Abel> struct UnionFind {

    vector<int> par;

    vector<int> rank;

    vector<Abel> diff_weight;



    UnionFind(int n = 1, Abel SUM_UNITY = 0) {

        init(n, SUM_UNITY);

    }



    void init(int n = 1, Abel SUM_UNITY = 0) {

        par.resize(n); rank.resize(n); diff_weight.resize(n);

        for (int i = 0; i < n; ++i) par[i] = i, rank[i] = 0, diff_weight[i] = SUM_UNITY;

    }



    int root(int x) {

        if (par[x] == x) {

            return x;

        }

        else {

            int r = root(par[x]);

            diff_weight[x] += diff_weight[par[x]];

            return par[x] = r;

        }

    }



    Abel weight(int x) {

        root(x);

        return diff_weight[x];

    }



    bool issame(int x, int y) {

        return root(x) == root(y);

    }



    bool merge(int x, int y, Abel w) {

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

        x = root(x); y = root(y);

        if (x == y) return false;

        if (rank[x] < rank[y]) swap(x, y), w = -w;

        if (rank[x] == rank[y]) ++rank[x];

        par[y] = x;

        diff_weight[y] = w;

        return true;

    }



    Abel diff(int x, int y) {

        return weight(y) - weight(x);

    }

};





int l[200010],r[200010],d[200010];

int main(){

    int n,m;

    cin>>n>>m;

    

    UnionFind<int> uni(n);

    

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

    {

        cin>>l[i]>>r[i]>>d[i];

        l[i]--;

        r[i]--;



    }

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

    {

        if(uni.issame(l[i],r[i])){

            int diff=uni.diff(l[i],r[i]);

            if(diff!=d[i]){

                cout<<"No"<<endl;

                return 0;

            }

        }

        else{

            uni.merge(l[i],r[i],d[i]);

        }

    }



    cout<<"Yes"<<endl;

   

    

    

   



    return 0;

}

// Fastest known solution for this problem: