// Original C++ solution (slower):
#include <iostream>

#include <cstdio>

#include <algorithm>

#include <cmath>

#include <vector>

#include <list>

#include <set>

#include <map>

#include <queue>

#include <stack>

#include <cctype>

#include <cassert>

#include <climits>

#include <string>

#include <bitset>

#include <cfloat>

#include <random>

#include <unordered_set>

#pragma GCC optimize("Ofast")

using namespace std;

typedef long double ld;

typedef long long int ll;

typedef unsigned long long int ull;

typedef vector<int> vi;

typedef vector<char> vc;

typedef vector<bool> vb;

typedef vector<double> vd;

typedef vector<string> vs;

typedef vector<ll> vll;

typedef vector<pair<int,int> > vpii;

typedef vector<vector<int> > vvi;

typedef vector<vector<char> > vvc;

typedef vector<vector<string> > vvs;

typedef vector<vector<ll> > vvll;

#define rep(i,n) for(int i = 0; i < (n); ++i)

#define rrep(i,n) for(int i = 1; i <= (n); ++i)

#define irep(it, stl) for(auto it = stl.begin(); it != stl.end(); it++)

#define drep(i,n) for(int i = (n) - 1; i >= 0; --i)

#define fin(ans) cout << (ans) << '\n'

#define STLL(s) strtoll(s.c_str(), NULL, 10)

#define mp(p,q) make_pair(p, q)

#define pb(n) push_back(n)

#define all(a) a.begin(), a.end()

#define rall(a) a.rbegin(), a.rend()

#define Sort(a) sort(a.begin(), a.end())

#define Rort(a) sort(a.rbegin(), a.rend())

#define MATHPI acos(-1)

#define itn int;

#define endl '\n';

const int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};

const int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

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;}

inline string getline(){string s; getline(cin,s); return s;}

inline void yn(const bool b){b?fin("yes"):fin("no");}

inline void Yn(const bool b){b?fin("Yes"):fin("No");}

inline void YN(const bool b){b?fin("YES"):fin("NO");}

struct io{io(){ios::sync_with_stdio(false);cin.tie(0);}};

const int INF = INT_MAX;

const ll LLINF = 1LL<<60;

const ll MOD = 1000000007;

const double EPS = 1e-9;





struct Corr{

    int pos;

    int w;

};



vi weight(101010, -1);

vi ispassed(101010,false);



bool dfs(Corr c, vector<vector<Corr>> &v){

    int res=1;

    rep(i,v[c.pos].size()){

        int nextPos=v[c.pos][i].pos;

        int nextW=c.w+v[c.pos][i].w;

        if(weight[nextPos]!=-1){

            if(nextW!=weight[nextPos])res=0;

        }

        if(ispassed[nextPos])continue;

        ispassed[nextPos]=1;

        weight[nextPos]=nextW;

        Corr next={nextPos, nextW};

        res*=dfs(next, v);

    }

    return res;

}



int main() {

    

    int n,m;

    cin>>n>>m;

    vector<vector<Corr>> v(n);

    rep(i,m){

        int l,r,d;

        cin>>l>>r>>d;

        l--;r--;

        Corr c={r,d};

        v[l].pb(c);

        c={l,-d};

        v[r].pb(c);

    }

    

    bool ans=1;

    rep(i,n){

        if(ispassed[i])continue;

        Corr c={i,0};

        weight[i]=0;

        ans*=dfs(c,v);

    }

    Yn(ans);

    // rep(i,10)fin(weight[i]);

}




// Optimized solution to the same problem (faster):
#include <iostream>

#include <cstdio>

#include <algorithm>

#include <cmath>

#include <vector>

#include <list>

#include <set>

#include <map>

#include <queue>

#include <stack>

#include <cctype>

#include <cassert>

#include <climits>

#include <string>

#include <bitset>

#include <cfloat>

#include <random>

#include <iomanip>

#include <unordered_set>

#pragma GCC optimize("Ofast")

using namespace std;

typedef long double ld;

typedef long long int ll;

typedef unsigned long long int ull;

typedef vector<int> vi;

typedef vector<char> vc;

typedef vector<bool> vb;

typedef vector<double> vd;

typedef vector<string> vs;

typedef vector<ll> vll;

typedef vector<pair<int,int> > vpii;

typedef vector<pair<ll,ll> > vpll;

typedef vector<vector<int> > vvi;

typedef vector<vector<char> > vvc;

typedef vector<vector<string> > vvs;

typedef vector<vector<ll> > vvll;

typedef map<int, int> mii;

typedef set<int> si;

#define rep(i,n) for(int i = 0; i < (n); ++i)

#define rrep(i,n) for(int i = 1; i <= (n); ++i)

#define irep(it, stl) for(auto it = stl.begin(); it != stl.end(); it++)

#define drep(i,n) for(int i = (n) - 1; i >= 0; --i)

#define fin(ans) cout << (ans) << '\n'

#define STLL(s) strtoll(s.c_str(), NULL, 10)

#define mp(p,q) make_pair(p, q)

#define pb(n) push_back(n)

#define all(a) a.begin(), a.end()

#define rall(a) a.rbegin(), a.rend()

#define Sort(a) sort(a.begin(), a.end())

#define Rort(a) sort(a.rbegin(), a.rend())

#define MATHPI acos(-1)

#define itn int

// #define endl '\n';

#define fi first

#define se second

#define NONVOID [[nodiscard]]

const int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};

const int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

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 T> inline void dump(T &v){irep(i, v){cout<<*i<<((i==--v.end())?'\n':' ');}}

inline string getline(){string s; getline(cin,s); return s;}

inline void yn(const bool b){b?fin("yes"):fin("no");}

inline void Yn(const bool b){b?fin("Yes"):fin("No");}

inline void YN(const bool b){b?fin("YES"):fin("NO");}

struct io{io(){ios::sync_with_stdio(false);cin.tie(0);}};

const int INF = INT_MAX;

const ll LLINF = 1LL<<60;

const ll MOD = 1000000007;

const double EPS = 1e-9;



class UnionFind {

public:

    // 親の番号を格納．親だった場合は-(その集合のサイズ)

    vector<int> Parent;

    // 重さの差を格納

    vector<ll> diffWeight;



    UnionFind(const int N) {

        Parent = vector<int>(N, -1);

        diffWeight = vector<ll>(N, 0);

    }



    // Aがどのグループに属しているか調べる

    int root(const int A) {

        if (Parent[A] < 0) return A;

        int Root = root(Parent[A]);

        diffWeight[A] += diffWeight[Parent[A]];

        return Parent[A] = Root;

    }



    // 自分のいるグループの頂点数を調べる

    int size(const int A) {

        return -Parent[root(A)];

    }



    // 自分の重さを調べる

    ll weight(const int A) {

        root(A); // 経路圧縮

        return diffWeight[A];

    }



    // 重さの差を計算する

    ll diff(const int A, const int B) {

        return weight(B) - weight(A);

    }



    // AとBをくっ付ける

    bool connect(int A, int B, ll W = 0) {

        // Wをrootとの重み差分に変更

        W += weight(A);

        W -= weight(B);



        // AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける

        A = root(A);

        B = root(B);



        if (A == B) {

            //すでにくっついてるからくっ付けない

            return false;

        }



        // 大きい方(A)に小さいほう(B)をくっ付ける

        // 大小が逆だったらひっくり返す

        if (size(A) < size(B)) {

            swap(A, B);

            W = -W;

        }



        // Aのサイズを更新する

        Parent[A] += Parent[B];

        // Bの親をAに変更する

        Parent[B] = A;



        // AはBの親であることが確定しているのでBにWの重みを充てる

        diffWeight[B] = W;



        return true;

    }

};





int main() {



    int n,m;

    cin>>n>>m;

    UnionFind uni(n);

    rep(i,m){

        int l,r,d;

        cin>>l>>r>>d;

        l--;r--;

        if(uni.root(l)!=uni.root(r))uni.connect(l,r,d);

        else {

            if(uni.diff(l,r)!=d){

                fin("No");

                return 0;

            }

        }

    }

    fin("Yes");

}


// Fastest known solution for this problem: