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

#include <cstdio>

#include <cstdlib>

#include <cmath>

#include <climits>

#include <cstring>

#include <string>

#include <vector>

#include <list>

#include <queue>

#include <stack>

#include <map>

#include <set>

#include <bitset>

#include <algorithm>

#include <functional>

#include <iomanip>

using namespace std;



#define LL long long

const int maxn = 100000 + 100;

struct Node {

    int pos;

    int dis;

    Node() {}

    Node(int p, int d) {

        pos = p;

        dis = d;

    }

};

int n, m, u, v, d;

bool flag;

int num[maxn], fa[maxn];

bool vis[maxn];

vector<Node> G[maxn];

queue<Node> que;



void Init() {

    flag = true;

    memset(vis, 0, sizeof(bool) * (n + 1));

    for(int i = 1; i <= n; ++i) {

        G[i].clear();

    }

    for(int i = 1; i <= n; ++i) {

        fa[i] = i;

    }

}



int Find(int x) {

    return (x == fa[x]? x: fa[x] = Find(fa[x]));

}



void unit(int x, int y) {

    int xx = Find(x);

    int yy = Find(y);

    fa[xx] = yy;

}



bool bfs(int x) {

    num[x] = 0;

    vis[x] = true;

    while(!que.empty()) {

        que.pop();

    }

    que.push(Node(x, 0));

    while(!que.empty()) {

        Node tmp = que.front();

        que.pop();

        int len = G[tmp.pos].size();

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

            int pos = G[tmp.pos][i].pos;

            int d = G[tmp.pos][i].dis;

            if(!vis[pos]) {

                vis[pos] = true;

                num[pos] = tmp.dis + d;

                que.push(Node(pos, num[pos]));

            } else if(num[pos] != tmp.dis + d) {

                return false;

            }

        }

    }

    return true;

}



int main() {

    #ifdef LOCAL

        freopen("test.txt", "r", stdin);

//    freopen("out.txt", "w", stdout);

    #endif // LOCAL

    ios::sync_with_stdio(false);



    while(scanf("%d%d", &n, &m) != EOF) {

        Init();

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

            scanf("%d%d%d", &u, &v, &d);

            G[u].push_back(Node(v, d));

            G[v].push_back(Node(u, -d));

            unit(v, u);

        }

        for(int i = 1; i <= n; ++i) {

            if(!vis[Find(i)]) {

                if(!bfs(Find(i))) {

                    flag = false;

                    break;

                }

            }

        }

        if(flag) {

            printf("Yes\n");

        } else {

            printf("No\n");

        }

    }



    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 3.4806966709537743x):
#include <bits/stdc++.h>



using namespace std;



#define int long long





vector<int> x;

vector<vector<pair<int, int>>>g;



vector<int> used;

void dfs(int v) {

    used[v] = 1;

    for (auto l: g[v]) {

        int to = l.first;

        int w = l.second;

        if (x[to] != -1) {

            if (x[v] + w != x[to]) {

                cout << "No";

                exit(0);

            }

        }

        else {

            x[to] = x[v] + w;

            if (!used[to]) dfs(to);

        }

    }

}



void solve() {

    int n;

    cin >> n;

    x.assign(n, -1);

    g.resize(n);

    used.resize(n);

    int m;

    cin >> m;

    set<int> st;

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

        int l, r, d;

        cin >> l >> r >> d;

        l--;

        r--;

        g[l].push_back({r, d});

        st.insert(r);

    }

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

        if (st.count(i)) continue;

        if (!used[i]) dfs(i);

    }

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

        if (!used[i]) {

            cout << "No";

            return;

        }

    }

    cout << "Yes";





}



signed main() {

    //freopen

    ios_base::sync_with_stdio(0);

    cin.tie(0);

    cout.tie(0);

    solve();

}

/*

5 5

4 5 1

5 1 1

1 2 1

2 3 1

4 3 4



 */