#include<bits/stdc++.h>
#define range(i,a,b) for(int i = (a); i < (b); i++)
#define rep(i,b) for(int i = 0; i < (b); i++)
#define all(a) (a).begin(), (a).end()
#define show(x)  cerr << #x << " = " << (x) << endl;
const int INF = 1e8;
using namespace std;


class Edge{
	public:
		int to, cost;
		Edge(int to, int cost) : to(to) ,cost(cost) {}
};

class Node{
	public:
		int dis;
		bool isUsed;
		Node(){
			this->dis = INF;
			this->isUsed = 0;
		}
};

typedef vector<vector<Edge>> AdjList;

bool dijkstra(AdjList g, int start, int n, vector<Node>& node){
	priority_queue<int, vector<pair<int, int>>, greater<pair<int, int>>> q;

	q.push(make_pair(0, start));
	node[start].dis = 0;

	pair<int, int> u;
	bool res = true;
	while(not q.empty()){
		u = q.top(); q.pop();
		int current = u.second;
		node[current].isUsed = 1;

		rep(i,g[current].size()){
			int next = g[current][i].to;
			if(node[next].isUsed == 0){
			if(node[next].dis != INF and node[next].dis != node[current].dis + g[current][i].cost){
				res = false;
			}
				if(node[next].dis > node[current].dis + g[current][i].cost){
					node[next].dis = node[current].dis + g[current][i].cost;
					q.push(make_pair(node[next].dis, next));
				}
			}
		}
	}
	return res;
}

int main(){
	int n, m;
	cin >> n >> m;

	AdjList g(n);
	rep(i,m){
		int l, r, c;
		cin >> l >> r >> c;
		l--; r--;
		g[l].emplace_back(r,c);
		g[r].emplace_back(l,c);
	}

	vector<Node> node(n);
	bool ans = true;
	rep(i,n){
		if(node[i].isUsed) continue;
		if(not dijkstra(g, i, n, node)) ans = false;
	}
	cout << (ans ? "Yes" : "No") << endl;
}
