// 基本テンプレート
 
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
using namespace std;
 
#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int
 
template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}
 
typedef pair<int, int> pii;
typedef long long ll;
 
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

// 移動元と行先と辺のコストを記録する構造体
template <typename T>
struct Edge {
    int from, to;
    T cost;
    Edge() {}
    Edge(int s, T d) : to(s), cost(d) {}
    Edge(int f, int s, T d) : from(f), to(s), cost(d) {}

    bool operator<(const Edge &e) const {
        return cost < e.cost;
    }
    bool operator>(const Edge &e) const {
        return cost > e.cost;
    }
};

template <typename T>
vector<int> tpsort_Kahn(const vector< vector< Edge<T> > > &g) {
    const int V = g.size();
    vector<int> indeg(V, 0);
    stack<int> S;

    rep(i,0,V) rep(j,0,g[i].size())
        indeg[ g[i][j].to ]++;
    rep(i,0,V) if(indeg[i] == 0) S.push(i);

    vector<int> ans;
    while(S.size() > 0) {
        int u = S.top(); S.pop();
        ans.push_back(u);
        rep(i,0,g[u].size()) {
            indeg[ g[u][i].to ]--;
            if(indeg[ g[u][i].to ] ==  0)
                S.push( g[u][i].to );
        }
    }
    return ans;
}

// to, cost
typedef vector< vector< Edge<int> > > Graph;
int N, M, deg[100010], dist[100010];
Edge<int> edges[200010];

signed main() {
    cin >> N >> M;
    Graph G(N);
    rep(i,0,M) {
        int L, R, D; cin >> L >> R >> D;
        L--; R--;
        G[L].push_back(Edge<int>(R, D));
        edges[i] = Edge<int>(L, R, D);
        deg[R]++;
    }

    vector<int> tp = tpsort_Kahn(G);
    if(tp.size() != N) {
        cout << "No" << endl;
        return 0;
    }

    fill(dist, dist+N, INF);
    rep(i,0,N) {
        if(deg[i] == 0) {
            dist[i] = 0;
            // cost, vertex
            priority_queue< pii, vector<pii>, greater<pii> > que;
            que.push(make_pair(0, i));

            while(que.size()) {
                pii cur = que.top(); que.pop();
                int v = cur.second, cost = cur.first;
                for(auto x : G[v]) {
                    if(dist[x.to] > dist[v] + x.cost) {
                        dist[x.to] = dist[v] + x.cost;
                        que.push(make_pair(dist[x.to], x.to));
                    }
                }
            }
        }
    }

    bool ok = true;
    rep(i,0,M) {
        Edge<int> e = edges[i];
        int u = e.from, v = e.to, d = e.cost;
        int diff = dist[v] - dist[u];
        ok &= (diff == d);
    }
    cout << (ok ? "Yes" : "No") << endl;
    return 0;
}

Measured memory_bytes: 19376