Problem:
Score : 400 points

Problem Statement

There are N people standing on the x-axis.
Let the coordinate of Person i be x_i.
For every i, x_i is an integer between 0 and 10^9 (inclusive).
It is possible that more than one person is standing at the same coordinate.

You will given M pieces of information regarding the positions of these people.
The i-th piece of information has the form (L_i, R_i, D_i).
This means that Person R_i is to the right of Person L_i by D_i units of distance, that is, x_{R_i} - x_{L_i} = D_i holds.

It turns out that some of these M pieces of information may be incorrect.
Determine if there exists a set of values (x_1, x_2, ..., x_N) that is consistent with the given pieces of information.

Constraints

1 \leq N \leq 100 000

0 \leq M \leq 200 000

1 \leq L_i, R_i \leq N (1 \leq i \leq M)

0 \leq D_i \leq 10 000 (1 \leq i \leq M)

L_i \neq R_i (1 \leq i \leq M)

If i \neq j, then (L_i, R_i) \neq (L_j, R_j) and (L_i, R_i) \neq (R_j, L_j).

D_i are integers.

Input

Input is given from Standard Input in the following format:

N M
L_1 R_1 D_1
L_2 R_2 D_2
:
L_M R_M D_M

Output

If there exists a set of values (x_1, x_2, ..., x_N) that is consistent with all given pieces of information, print Yes; if it does not exist, print No.

Sample Input 1

3 3
1 2 1
2 3 1
1 3 2

Sample Output 1

Yes

Some possible sets of values (x_1, x_2, x_3) are (0, 1, 2) and (101, 102, 103).

Sample Input 2

3 3
1 2 1
2 3 1
1 3 5

Sample Output 2

No

If the first two pieces of information are correct, x_3 - x_1 = 2 holds, which is contradictory to the last piece of information.

Sample Input 3

4 3
2 1 1
2 3 5
3 4 2

Sample Output 3

Yes

Sample Input 4

10 3
8 7 100
7 9 100
9 8 100

Sample Output 4

No

Sample Input 5

100 0

Sample Output 5

Yes

Solution in C++14 (GCC 5.4.1) (judge verdict: Time Limit Exceeded)

#include<iostream>
#include <list>
#include<stack>
#include<queue>
#include <vector>
#include <set>
#include<algorithm>
#include<math.h>
#include<stdlib.h>
#include<string>
#include <functional>
#include<map>

#define FOR(k,m,n) for(int (k)=(m);(k)<(n);(k)++)
#define REP(i,n) FOR((i),0,(n))
#define LL long long
#define CLR(a) memset((a),0,sizeof(a))
#define SZ(x) (int((x).size()))
#define WAITING(str) int str;std::cin>>str;
#define DEBUGING(str) cout<<str<<endl
using namespace std;

const LL MOD = 1000000007;// 10^9+7
const int INF = (1 << 30);


//変数
int N, M;
bool ans = true;
vector<map<int, int>> edge;// edge[from][to] = length





//サブ関数
//入力
void input()
{
	cin >> N >> M;
	edge.resize(N);
	int l, r, d;
	REP(i, M) {
		cin >> l >> r >> d;
		l--; r--;
		edge[l][r] = d;
		edge[r][l] = -d;
	}
}


//vectorの中身を全部表示
template<typename T>
void show(vector<T> v)
{
	for (auto col : v)cout << col << " ";
	cout << endl;
}
template<typename T>
void show(vector<vector<T>> v)
{
	for (auto row : v)show(row);
	cout << endl;
}



//計算
void calc()
{
	vector<bool> went(N, false);
	vector<int> place(N, INF);
	queue<pair<int, int>> q;// first:from,  second:to
	


	REP(i, N) 
	{
		//枝切り
		if (went[i])continue;
		if (edge[i].size() == 0)continue;


		//init
		place = vector<int>(N, INF);
		place[i] = 0;
		went[i] = true;
		for (auto itr = edge[i].begin(); itr != edge[i].end(); ++itr) {
			q.push(make_pair(i, itr->first));
		}

		//各枝を確認していく
		while (!q.empty()) {
			auto now = q.front(); q.pop();
			went[now.first] = true;
			int will = place[now.first] + edge[now.first][now.second];

			//show(place);
			//cout << now.first << " " << now.second << endl << endl;

			//既に探索済みに移行している場合
			if (place[now.second] != INF) {
				//食い違いが出たら、終了
				if (place[now.second] != will) {
					ans = false;
					break;
				}
			}
			else {
				//場所を更新
				place[now.second] = will;

				//そこから行ける道を、とりあえず全部ぶち込む
				for (auto itr = edge[now.second].begin(); itr != edge[now.second].end(); ++itr) {
					q.push(make_pair(now.second, itr->first));
				}
			}
		}
		//show(place);
	}

}


//出力
void output()
{
	cout << (ans ? "Yes" : "No") << endl;
}


//デバッグ
void debug()
{
	int N;
	cin>>N;
}


//メイン関数
int main()
{
	input();
	calc();
	output();
	debug();
	
	return 0;
}