// 基本テンプレート
 
#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;

int N, M;

// 移動元と行先と辺のコストを記録する構造体
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>
using Graph = vector< vector< Edge<T> > >;

// Kahnのトポロジカルソートアルゴリズム (Verified: AOJ GRL_4_B: Topological Sort)
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;
}

Edge<int> edges[200010];
int dist[100010], deg[100010];
Graph<int> G;
void solve(int u) {
    // cost, pos
    priority_queue< pii, vector<pii>, greater<pii> > que;
    dist[u] = 0;
    que.push(make_pair(0, u));

    while(que.size()) {
        pii cur = que.top(); que.pop();
        for(auto e : G[cur.second]) {
            if(dist[e.to] > dist[cur.second] + e.cost) {
                dist[e.to] = dist[cur.second] + e.cost;
                que.push(make_pair(dist[e.to], e.to));
            }
        }
    }
}
 
signed main() {
    cin >> N >> M;

    G.resize(N);
    rep(i,0,M) {
        int l, r, d; cin >> l >> r >> d;
        l--; r--;
        G[l].push_back(Edge<int>(r, d));
        deg[r]++;
        edges[i] = Edge<int>(l, r, d);
    }

    vector<int> tp = tpsort_Kahn(G);
    if(tp.size() != N) cout << "No" << endl;
    else {
        rep(i,0,N) dist[i] = INF;
        rep(i,0,N) if(!deg[i]) solve(i);

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

Measured memory_bytes: 19376