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

#include <vector>



using namespace std;



struct edge {

    int to, cost;

};



vector<edge> G[200010];

bool vis[100010];

int d[100010];



bool dfs(int v, int dist) {

    if (vis[v]) {

        if (d[v] != dist) {

            return true;

        }

        else {

            return false;

        }

    }

    vis[v] = true;

    d[v] = dist;

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

        if (dfs(G[v][i].to, d[v] + G[v][i].cost)) {

            return true;//その頂点における判定で一つでも矛盾があれば、全てtrueを返して終了。

        }

        //何も矛盾が無ければ次のリストを見る。

    }

    return false;//連結している頂点が最後まで探索できたという証。

}



int main() {

    int N, M;

    cin >> N >> M;



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

        int L, R, D;

        cin >> L >> R >> D;

        L--; R--;

        G[L].push_back({ R,D });

        G[R].push_back({ L,-D });

    }

    for (int i = 0; i < N; i++) {//連結していない頂点があった場合に探索していく

        if (!vis[i] && dfs(i, 0)) {

            cout << "No" << endl;

            return 0;

        }

    }

    cout << "Yes" << endl;

}

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

#include <string>

#include <vector>

#include <list>

#include <algorithm>

#include <numeric>

#include <cmath>

#include <set>

#include <map>

#include <queue>

#include <stack>

#include <functional>

#include <utility>

#include <fstream>



using namespace std;



#define ll long long

#define INF 2000000000

#define LINF 9000000000000000000

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

#define dum(x) cout<<#x<<'='<<x<<endl

#define dum2(x,y) cout<<#x<<'='<<x<<' '<<#y<<'='<<y<<'\n'<<endl

#define dum3(x,y,z) cout<<#x<<'='<<x<<' '<<#y<<'='<<y<<' '<<#z<<'='<<z<<'\n'<<endl

#define darr(arr,n) rep(i,(n-arr)){cout<<*(arr+i)<<' ';}cout<<endl

#define ddarr(arr,a,b) rep(i,a){rep(j,b){cout<<*(arr+i*b+j)<<' ';}cout<<endl;}

#define ddd ifstream in("Text.txt");cin.rdbuf(in.rdbuf());



template<class Abel> struct unionfind {

    vector<int> par;

    vector<int> sizes;

    vector<Abel> wei;



    unionfind(int N, Abel uni = 0) : par(N), sizes(N, 1), wei(N, uni) {

        for (int i = 0; i < N; i++) par[i] = i;

    }



    int parfind(int x) {

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

        int r = parfind(par[x]);

        wei[x] += wei[par[x]];

        return par[x] = r;

    }



    Abel weight(int x) {

        parfind(x);

        return wei[x];

    }



    void unite(int x, int y, Abel w) {

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

        x = parfind(x); y = parfind(y);

        if (x == y) return;

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

        par[y] = x;

        wei[y] = w;

        sizes[x] += sizes[y];

    }



    bool same(int x, int y) {

        return parfind(x) == parfind(y);

    }

    Abel diff(int x, int y) {

        return weight(y) - weight(x);

    }

    int size(int x) {

        return sizes[parfind(x)];

    }

};



int main() {

    int N, M;

    cin >> N >> M;

    unionfind<int> uf(N);

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

        int L, R, D;

        cin >> L >> R >> D;

        --L, --R;

        if (uf.same(L, R)) {

            int diff = uf.diff(L, R);

            if (diff != D) {

                cout << "No" << endl;

                return 0;

            }

        }

        else {

            uf.unite(L, R, D);

        }

    }

    cout << "Yes" << endl;

}

// Fastest known solution for this problem: