// Slower C++ solution:
#include <iostream>

#include <cstdio>

#include <string>

#include <algorithm>

#include <utility>

#include <cmath>

#include <vector>

#include <queue>

#include <set>

#include <map>

using namespace std;

typedef long long ll;

typedef vector<ll> vl;

typedef vector<vector<ll>> vvl;

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

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

#define exrep(i, a, b) for(ll i = a; i <= b; i++)

#define out(x) cout << x << endl

#define exout(x) printf("%.10f\n", x)

#define chmax(x, y) x = max(x, y)

#define chmin(x, y) x = min(x, y)

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

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

#define pb push_back

#define re0 return 0

const ll mod = 1000000007;

const ll INF = 1e16;

const ll MAX_N = 100010;



vvpll G;

vl visited;

vl d(MAX_N);

bool ok = true;



void dfs(ll v, ll dist) {

    if(visited[v]) {

        if(d[v] != dist) {

            ok = false;

            return;

        }

        return;

    }

    visited[v] = 1;

    d[v] = dist;

    for(auto p : G[v]) {

        ll u = p.first;

        ll cost = p.second;

        dfs(u, d[v] + cost);

    }

    return;

}



int main() {

    ll n, m;

    cin >> n >> m;    



    G.resize(n);

    rep(i, m) {

        ll L, R, D;

        cin >> L >> R >> D;

        L--;  R--;

        G[L].pb(make_pair(R, D));

        G[R].pb(make_pair(L, -D));

    }



    visited.resize(n);

    rep(v, n) {

        if(!visited[v]) {

            dfs(v, 0);

        }

    }



    if(ok) {

        out("Yes");

    }

    else {

        out("No");

    }

    

    re0;

}

// Faster C++ solution for the same problem (measured speedup: 1.807111463149352x):
#include <iostream>

#include <cstdio>

#include <string>

#include <algorithm>

#include <utility>

#include <cmath>

#include <vector>

#include <queue>

#include <set>

#include <map>

#include <tuple>

#include <numeric>

#include <functional>

using namespace std;

typedef long long ll;

typedef vector<ll> vl;

typedef vector<vector<ll>> vvl;

typedef pair<ll, ll> P;

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

#define exrep(i, a, b) for(ll i = a; i <= b; i++)

#define out(x) cout << x << endl

#define exout(x) printf("%.10f\n", x)

#define chmax(x, y) x = max(x, y)

#define chmin(x, y) x = min(x, y)

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

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

#define pb push_back

#define re0 return 0

const ll mod = 1000000007;

const ll INF = 1e16;

const ll MAX_N = 100000;



vector<vector<P>> G;

vl visited;  // visted[v] : 頂点vを訪問済みなら1

vl height;  // height[v] : 頂点vの高さ

bool ok = true;  // 条件が矛盾していないならtrue



void dfs(ll v, ll h = 0) {  // いまいる頂点v、vの高さ

    // 行きの処理はこのへんに書く

    if(visited[v]) {

        if(height[v] != h) {

            ok = false;

        }

        return;

    }

    visited[v] = 1;

    height[v] = h;

    for(auto p : G[v]) { 

        ll u = p.first;

        ll cost = p.second;

        dfs(u, h + cost);

        // 帰りの処理はこのへんに書く

    }

}



int main() {

    ll n, m;

    cin >> n >> m;    

    

    G.resize(n);

    rep(i, m) {

        ll a, b, cost;

        cin >> a >> b >> cost;

        a--;  b--;

        G[a].pb(make_pair(b, cost));

        G[b].pb(make_pair(a, -cost));

    }

    

    height.resize(n);

    visited.resize(n);

    rep(v, n) {

        if(visited[v]) {

            continue;

        }

        dfs(v);

    }



    if(ok) {

        out("Yes");

    }

    else {

        out("No");

    }



    re0;

}