Problem: 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`.

Examples

Input

3 3
1 2 1
2 3 1
1 3 2


Output

Yes


Input

3 3
1 2 1
2 3 1
1 3 5


Output

No


Input

4 3
2 1 1
2 3 5
3 4 2


Output

Yes


Input

10 3
8 7 100
7 9 100
9 8 100


Output

No


Input

100 0


Output

Yes

Solution (in JAVA):

Solution:
import java.io.*;
import java.util.*;

public class Main {

	private static Scanner sc;
	private static Printer pr;

	private static void solve() {
		int n = sc.nextInt();
		int m = sc.nextInt();

		int[] l = new int[m];
		int[] r = new int[m];
		int[] d = new int[m];
		List<Queue<Integer>> list2 = new ArrayList<>(n);
		for (int i = 0; i < n; i++) {
			list2.add(new ArrayDeque<>());
		}
		for (int i = 0; i < m; i++) {
			l[i] = sc.nextInt() - 1;
			r[i] = sc.nextInt() - 1;
			d[i] = sc.nextInt();

			list2.get(l[i]).add(i);
			list2.get(r[i]).add(i);
		}

		BitSet done = new BitSet(m);
		for (int i = 0; i < m; i++) {
			if (done.get(i)) {
				continue;
			}

			Map<Integer, Long> hm = new HashMap<>();

			Queue<Integer> q = new ArrayDeque<>();
			q.addAll(list2.get(l[i]));
			list2.get(l[i]).clear();
			q.addAll(list2.get(r[i]));
			list2.get(r[i]).clear();
			while (!q.isEmpty()) {
				int e = q.remove();
				if (done.get(e)) {
					continue;
				}
				done.set(e);

				q.addAll(list2.get(l[e]));
				list2.get(l[e]).clear();
				q.addAll(list2.get(r[e]));
				list2.get(r[e]).clear();

				Long dl = hm.get(l[e]);
				Long dr = hm.get(r[e]);
				if (dl != null && dr != null) {
					if (dr - dl != d[e]) {
						pr.println("No");
						return;
					}
				} else if (dl != null && dr == null) {
					hm.put(r[e], dl + d[e]);
				} else if (dl == null && dr != null) {
					hm.put(l[e], dr - d[e]);
				} else {
					hm.put(l[e], 0L);
					hm.put(r[e], 0L + d[e]);
				}
			}

			long max = Long.MIN_VALUE;
			long min = Long.MAX_VALUE;
			for (long ee : hm.values()) {
				max = Math.max(max, ee);
				min = Math.min(min, ee);
			}

			if (max - min > 1_000_000_000) {
				pr.println("No");
				return;
			}
		}

		pr.println("Yes");
	}

	@SuppressWarnings("unused")
	private static class UnionFind {
		int n;
		// cnt : 異なる集合の数
		int cnt;
		// parent[x] : 0～n-1 の場合、要素xのroot要素
		//           : -1～-n の場合、自分自身がroot要素、
		//                            -parent[x]でxを含む集合の要素数
		int[] parent;
		// rank[x] : 要素xが属する木の高さ
		int[] rank;

		UnionFind(int n) {
			this.n = n;
			cnt = n;
			parent = new int[n];
			Arrays.fill(parent, -1);
			rank = new int[n];
			Arrays.fill(rank, 0);
		}

		// xのrootを求める
		int find(int x) {
			if (parent[x] < 0) {
				return x;
			} else {
				return parent[x] = find(parent[x]);
			}
		}

		// xとyが同じ集合に属するのか
		boolean same(int x, int y) {
			return find(x) == find(y);
		}

		// xとyの属する集合を併合する
		void unite(int x, int y) {
			x = find(x);
			y = find(y);
			if (x == y) {
				return;
			}

			cnt--;
			// rankが大きい集合をrootにする
			if (rank[x] > rank[y]) {
				parent[x] += parent[y];
				parent[y] = x;
			} else {
				parent[y] += parent[x];
				parent[x] = y;
				if (rank[x] == rank[y]) {
					rank[y]++;
				}
			}

			return;
		}

		// 要素xを含む集合の要素数
		int count(int x) {
			return -parent[find(x)];
		}

		// 異なる集合の数
		int count() {
			return cnt;
		}
	}

	// ---------------------------------------------------
	public static void main(String[] args) {
		sc = new Scanner(System.in);
		pr = new Printer(System.out);

		solve();

		pr.close();
		sc.close();
	}

	@SuppressWarnings("unused")
	private static class Scanner {
		BufferedReader br;

		Scanner (InputStream in) {
			br = new BufferedReader(new InputStreamReader(in));
		}

		private boolean isPrintable(int ch) {
			return ch >= '!' && ch <= '~';
		}

		private boolean isCRLF(int ch) {
			return ch == '\n' || ch == '\r' || ch == -1;
		}

		private int nextPrintable() {
			try {
				int ch;
				while (!isPrintable(ch = br.read())) {
					if (ch == -1) {
						throw new NoSuchElementException();
					}
				}

				return ch;
			} catch (IOException e) {
				throw new NoSuchElementException();
			}
		}

		String next() {
			try {
				int ch = nextPrintable();
				StringBuilder sb = new StringBuilder();
				do {
					sb.appendCodePoint(ch);
				} while (isPrintable(ch = br.read()));

				return sb.toString();
			} catch (IOException e) {
				throw new NoSuchElementException();
			}
		}

		int nextInt() {
			try {
				// parseInt from Integer.parseInt()
				boolean negative = false;
				int res = 0;
				int limit = -Integer.MAX_VALUE;
				int radix = 10;

				int fc = nextPrintable();
				if (fc < '0') {
					if (fc == '-') {
						negative = true;
						limit = Integer.MIN_VALUE;
					} else if (fc != '+') {
						throw new NumberFormatException();
					}
					fc = br.read();
				}
				int multmin = limit / radix;

				int ch = fc;
				do {
					int digit = ch - '0';
					if (digit < 0 || digit >= radix) {
						throw new NumberFormatException();
					}
					if (res < multmin) {
						throw new NumberFormatException();
					}
					res *= radix;
					if (res < limit + digit) {
						throw new NumberFormatException();
					}
					res -= digit;

				} while (isPrintable(ch = br.read()));

				return negative ? res : -res;
			} catch (IOException e) {
				throw new NoSuchElementException();
			}
		}

		long nextLong() {
			try {
				// parseLong from Long.parseLong()
				boolean negative = false;
				long res = 0;
				long limit = -Long.MAX_VALUE;
				int radix = 10;

				int fc = nextPrintable();
				if (fc < '0') {
					if (fc == '-') {
						negative = true;
						limit = Long.MIN_VALUE;
					} else if (fc != '+') {
						throw new NumberFormatException();
					}
					fc = br.read();
				}
				long multmin = limit / radix;

				int ch = fc;
				do {
					int digit = ch - '0';
					if (digit < 0 || digit >= radix) {
						throw new NumberFormatException();
					}
					if (res < multmin) {
						throw new NumberFormatException();
					}
					res *= radix;
					if (res < limit + digit) {
						throw new NumberFormatException();
					}
					res -= digit;

				} while (isPrintable(ch = br.read()));

				return negative ? res : -res;
			} catch (IOException e) {
				throw new NoSuchElementException();
			}
		}

		float nextFloat() {
			return Float.parseFloat(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

		String nextLine() {
			try {
				int ch;
				while (isCRLF(ch = br.read())) {
					if (ch == -1) {
						throw new NoSuchElementException();
					}
				}
				StringBuilder sb = new StringBuilder();
				do {
					sb.appendCodePoint(ch);
				} while (!isCRLF(ch = br.read()));

				return sb.toString();
			} catch (IOException e) {
				throw new NoSuchElementException();
			}
		}

		void close() {
			try {
				br.close();
			} catch (IOException e) {
//				throw new NoSuchElementException();
			}
		}
	}

	private static class Printer extends PrintWriter {
		Printer(PrintStream out) {
			super(out);
		}
	}
}