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

#include<string>

#include<cstdio>

#include<cmath>

#include<cstring>

#include<algorithm>

#include<vector>

#include<functional>

#include<iomanip>

#include<queue>

#include<cassert>

#include<tuple>

#include<set>

#include<map>

#include<list>

#include<bitset>



#define PB push_back

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

#define DWN(a)  (a).begin(),(a).end(), greater<int>()

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

#define REP(i, n, m) for (int i = n; i < m; i++)



#define mod 1000000007



using namespace std;



typedef long long ll;

typedef pair<int, int> P;



const int dx[4] = { 1, 0, -1, 0 };

const int dy[4] = { 0, 1, 0, -1 };

const int INF = (int)1e9;



struct edge {

	int to, cost;

};

vector<edge> G[100010];

vector<int> vis(100010, INF);



bool res = true;



void bfs(int k) {

	queue<P> que;

	que.push(P(k, 0));

	vis[k] = 0;

	

	while (!que.empty()) {

		P p = que.front();

		que.pop();

		int s = p.first;

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

			edge e = G[s][i];

			if (vis[e.to] == INF) {

				vis[e.to] = vis[s] + e.cost;

				que.push(P(e.to, vis[e.to]));

			}

			else if (vis[e.to] != vis[s] + e.cost) {

				res = false;

			}

		}

	}

}



int main()

{

	int N, M;

	cin >> N >> M;

	int l, r, d;

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

		cin >> l >> r >> d;

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

		G[r].push_back(edge{ l, -d });

	}

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

		if (vis[i] == INF && G[i].size() != 0) bfs(i);

	}

	if (res) {

		cout << "Yes" << endl;

	}

	else {

		cout << "No" << endl;

	}

	return 0;

}

// Optimized solution to the same problem (faster):
#include "bits/stdc++.h"

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 REP(i, a, b) for(ll i = a; i <= b; i++)

#define out(x) std::cout << x << '\n'

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

#define pb push_back

#define sz(x) ((int)(x).size())

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

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

ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }

ll lcm(ll a, ll b) { ll g = gcd(a, b); return a / g * b; }

const int dx[4] = { 1, 0, -1,  0 };

const int dy[4] = { 0, 1,  0, -1 };

const int INF = (int)1e9;

const ll  inf = (ll)1e18;

const int mod = 1000000007;

const int MAX_N = 100010;



template<class Abel> struct UnionFind {

	vector<int> par;

	vector<int> rank;

	vector<Abel> diff_weight;



	UnionFind(int n = 1, Abel SUM_UNITY = 0) {

		init(n, SUM_UNITY);

	}



	void init(int n = 1, Abel SUM_UNITY = 0) {

		par.resize(n); rank.resize(n); diff_weight.resize(n);

		for (int i = 0; i < n; ++i) par[i] = i, rank[i] = 0, diff_weight[i] = SUM_UNITY;

	}



	int root(int x) {

		if (par[x] == x) {

			return x;

		}

		else {

			int r = root(par[x]);

			diff_weight[x] += diff_weight[par[x]];

			return par[x] = r;

		}

	}



	Abel weight(int x) {

		root(x);

		return diff_weight[x];

	}



	bool issame(int x, int y) {

		return root(x) == root(y);

	}



	bool merge(int x, int y, Abel w) {

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

		x = root(x); y = root(y);

		if (x == y) return false;

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

		if (rank[x] == rank[y]) ++rank[x];

		par[y] = x;

		diff_weight[y] = w;

		return true;

	}



	Abel diff(int x, int y) {

		return weight(y) - weight(x);

	}

};



int main() {

	cin.tie(0);

	ios::sync_with_stdio(false);

	cout << fixed << setprecision(10);

	/*------------------------------*/



	int n, m;

	cin >> n >> m;

	

	UnionFind<int> uf(n);

	

	rep(i, m) {

		int l, r, d;

		cin >> l >> r >> d;

		l--; r--;

		if (uf.issame(l, r)) {

			int ud = uf.diff(l, r);

			if (d != ud) {

				out("No");

				return 0;

			}

		}

		else {

			uf.merge(l, r, d);

		}

	}



	out("Yes");



	return 0;

}

// Fastest known solution for this problem: