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



Sample input:
3 3
1 2 1
2 3 1
1 3 2


Sample output:
Yes

Submission status: Time Limit Exceeded

Solution code:
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time,copy,functools
from collections import deque

sys.setrecursionlimit(10**7)
inf = 10**20
mod = 10**9 + 7

DR = [1, -1, 0, 0]
DC = [0, 0, 1, -1]

def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI_(): return [int(x)-1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def I(): return int(sys.stdin.readline())
def F(): return float(sys.stdin.readline())
def S(): return input()
     

def main():
    N, M = LI()
    if M == 0:
        print("Yes")
        return

    G = [[] for _ in range(N)]
    for i in range(M):
        l, r, d = LI()
        l -= 1
        r -= 1
        G[l].append((r, d))
        G[r].append((l, -d))
    val = [inf] * N
    global_visited = set()

    def bfs(ini):
        flag = True
        q = deque([ini])
        visited = set()
        visited.add(ini)
        while q:
            v = q.popleft()
            for next_v, d in G[v]:
                if next_v in visited:
                    if val[next_v] == val[v] + d:
                        continue
                    else:
                        flag = False
                        break
                val[next_v] = val[v] + d
                visited.add(next_v)
                global_visited.add(next_v)
                q.append(next_v)
        if flag:
            return True
        return False

    can = True
    for i in range(N):
        if i in global_visited:
            continue
        v = i
        val[v] = 0
        if not bfs(v):
            can = False

    if can:
        print("Yes")
    else:
        print("No")
    return




main()

Submission status: Time Limit Exceeded

Solution code:
from collections import deque
import sys
sys.setrecursionlimit(1000)

n,m=map(int,input().split())
edge=[[] for _ in range(n)]
for i in range(m):
    l,r,d=map(int,input().split())
    edge[l-1].append((r-1,d))
    edge[r-1].append((l-1,-d))

top=[False]*n

for i in range(n):
    memo=[False]*n
    if top[i]:
        l=deque([(i,top[i])])
        memo[i]=top[i]
    else:
        l=deque([(i,0)])
        memo[i]=0
    while l:
        now=l.popleft()
        for to in edge[now[0]]:
            if memo[to[0]]:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        continue
                    else:
                        print("No")
                        exit()
                else:
                    top[to[0]]=to[1]+memo[now[0]]
                    continue
            else:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        memo[to[0]]=top[to[0]]
                        l.append((to[0],memo[to[0]]))
                    else:
                        print("No")
                        exit()
                else:
                    memo[to[0]]=to[1]+memo[now[0]]
                    top[to[0]]=to[1]+memo[now[0]]
                    l.append((to[0],memo[to[0]]))


print("Yes")

Submission status: Time Limit Exceeded

Solution code:
from collections import deque
import sys
sys.setrecursionlimit(1000)

n,m=map(int,input().split())
edge=[[] for _ in range(n)]
for i in range(m):
    l,r,d=map(int,input().split())
    edge[l-1].append((r-1,d))
    edge[r-1].append((l-1,-d))

top=[False]*n

for i in range(n):
    memo=[False]*n
    if top[i]:
        l=deque([(i,top[i])])
        memo[i]=top[i]
    else:
        l=deque([(i,0)])
        memo[i]=0
    while l:
        now=l.popleft()
        for to in edge[now[0]]:
            if memo[to[0]]:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        continue
                    else:
                        print("No")
                        exit()
                else:
                    top[to[0]]=to[1]+memo[now[0]]
                    l.append((to[0],memo[to[0]]))
            else:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        memo[to[0]]=top[to[0]]
                        l.append((to[0],memo[to[0]]))
                    else:
                        print("No")
                        exit()
                else:
                    memo[to[0]]=to[1]+memo[now[0]]
                    top[to[0]]=to[1]+memo[now[0]]
                    l.append((to[0],memo[to[0]]))


print("Yes")

Submission status: Time Limit Exceeded

Solution code:
from collections import deque
import sys
sys.setrecursionlimit(1000)

n,m=map(int,input().split())
edge=[[] for _ in range(n)]
for i in range(m):
    l,r,d=map(int,input().split())
    edge[l-1].append((r-1,d))
    edge[r-1].append((l-1,-d))

top=[False]*n

for i in range(n):
    memo=[False]*n
    if top[i]:
        l=deque([(i,top[i])])
        memo[i]=top[i]
    else:
        l=deque([(i,0)])
        memo[i]=0
    while l:
        now=l.popleft()
        for to in edge[now[0]]:
            if memo[to[0]]:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        continue
                    else:
                        print("No")
                        exit()
                else:
                    top[to[0]]=to[1]+memo[now[0]]
            else:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        memo[to[0]]=top[to[0]]
                    else:
                        print("No")
                        exit()
                else:
                    memo[to[0]]=to[1]+memo[now[0]]
                    top[to[0]]=to[1]+memo[now[0]]
            l.append((to[0],memo[to[0]]))


print("Yes")

Submission status: Time Limit Exceeded

Solution code:
from collections import deque
import sys
sys.setrecursionlimit(10**5)

n,m=map(int,input().split())
edge=[[] for _ in range(n)]
for i in range(m):
    l,r,d=map(int,input().split())
    edge[l-1].append((r-1,d))
    edge[r-1].append((l-1,-d))

top=[False]*n

for i in range(n):
    memo=[False]*n
    if top[i]:
        l=deque([(i,top[i])])
        memo[i]=top[i]
    else:
        l=deque([(i,0)])
        memo[i]=0
    while l:
        now=l.popleft()
        for to in edge[now[0]]:
            if memo[to[0]]:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        continue
                    else:
                        print("No")
                        exit()
                else:
                    top[to[0]]=to[1]+memo[now[0]]
            else:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        memo[to[0]]=top[to[0]]
                    else:
                        print("No")
                        exit()
                else:
                    memo[to[0]]=to[1]+memo[now[0]]
                    top[to[0]]=to[1]+memo[now[0]]
            l.append((to[0],memo[to[0]]))


print("Yes")

Submission status: Time Limit Exceeded

Solution code:
from collections import deque

n,m=map(int,input().split())
edge=[[] for _ in range(n)]
for i in range(m):
    l,r,d=map(int,input().split())
    edge[l-1].append((r-1,d))
    edge[r-1].append((l-1,-d))

top=[False]*n

for i in range(n):
    memo=[False]*n
    if top[i]:
        l=deque([(i,top[i])])
        memo[i]=top[i]
    else:
        l=deque([(i,0)])
        memo[i]=0
    while l:
        now=l.popleft()
        for to in edge[now[0]]:
            if memo[to[0]]:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        continue
                    else:
                        print("No")
                        exit()
                else:
                    top[to[0]]=to[1]+memo[now[0]]
            else:
                if top[to[0]]:
                    if top[to[0]]==to[1]+memo[now[0]]:
                        memo[to[0]]=top[to[0]]
                    else:
                        print("No")
                        exit()
                else:
                    memo[to[0]]=to[1]+memo[now[0]]
                    top[to[0]]=to[1]+memo[now[0]]
            l.append((to[0],memo[to[0]]))


print("Yes")

Submission status: Time Limit Exceeded

Solution code:
n, m = map(int, input().split())
G = [[] for _ in range(n)]
indeg = [0] * n

for _ in range(m):
    l, r, d = map(int, input().split())
    l -= 1
    r -= 1
    G[r].append((l, d))
    indeg[r] += 1

from collections import deque
ng = False
visited = [0] * n
for start, deg in enumerate(indeg):
    if deg == 0 or visited[start] == 1:
        continue
    st = deque([[start, 0]])
    visited_cost = [-1] * n
    while st:
        i, cost = st.pop()
        for ni, nd in G[i]:
            if visited_cost[ni] == -1:
                # まだ記録されていない
                visited[ni] = 1
                visited_cost[ni] = cost + nd
                st.append([ni, cost + nd])
            elif visited_cost[ni] == cost + nd:
                visited[ni] = 1
                continue
            else:
                # 既に記録されていて、矛盾している場合
                # 終了
                ng = True
                break
        if ng:
            break
    if ng:
        break

print('No' if ng else 'Yes')

Submission status: Time Limit Exceeded

Solution code:
n, m = map(int, input().split())
G = [[] for _ in range(n)]
indeg = [0] * n

for _ in range(m):
    l, r, d = map(int, input().split())
    l -= 1
    r -= 1
    G[r].append((l, d))
    indeg[r] += 1

from collections import deque
ng = False
visited = [0] * n
for start, deg in enumerate(indeg):
    if deg == 0 or visited[start] == 1:
        continue
    st = deque([[start, 0]])
    visited_cost = [-1] * n
    while st:
        i, cost = st.pop()
        for ni, nd in G[i]:
            if visited_cost[ni] == -1:
                # まだ記録されていない
                visited_cost[ni] = cost + nd
                st.append([ni, cost + nd])
            elif visited_cost[ni] == cost + nd:
                visited[ni] = 1
                continue
            else:
                # 既に記録されていて、矛盾している場合
                # 終了
                ng = True
                break
        if ng:
            break
    if ng:
        break

print('No' if ng else 'Yes')

Submission status: Time Limit Exceeded

Solution code:
n, m = map(int, input().split())
G = [[] for _ in range(n)]
indeg = [0] * n

for _ in range(m):
    l, r, d = map(int, input().split())
    l -= 1
    r -= 1
    G[r].append((l, d))
    indeg[r] += 1

from collections import deque
ng = False
for start, deg in enumerate(indeg):
    if deg == 0:
        continue
    st = deque([[start, 0]])
    visited_cost = [-1] * n
    while st:
        i, cost = st.pop()
        for ni, nd in G[i]:
            if visited_cost[ni] == -1:
                # まだ記録されていない
                visited_cost[ni] = cost + nd
                st.append([ni, cost + nd])
            elif visited_cost[ni] == cost + nd:
                # 既に記録されていて、矛盾していない場合
                # これ以上探索の必要がない
                continue
            else:
                # 既に記録されていて、矛盾している場合
                # 終了
                ng = True
                break
        if ng:
            break
    if ng:
        break

print('No' if ng else 'Yes')

Submission status: Time Limit Exceeded

Solution code:
n, m = map(int, input().split())
G = [[] for _ in range(n)]
indeg = [0] * n

for _ in range(m):
    l, r, d = map(int, input().split())
    l -= 1
    r -= 1
    G[r].append((l, d))
    indeg[r] += 1

from collections import deque
ng = False
for start, deg in enumerate(indeg):
    if deg == 0:
        continue
    st = deque([[start, 0]])
    visited_cost = [-1] * n
    while st:
        i, cost = st.pop()
        for ni, nd in G[i]:
            if visited_cost[ni] == -1 or visited_cost[ni] == cost + nd:
                # まだ記録されていない
                # 既に記録されていて、矛盾していない場合
                visited_cost[ni] = cost + nd
                st.append([ni, cost + nd])
            else:
                # 既に記録されていて、矛盾している場合
                # 終了
                ng = True
                break
        if ng:
            break
    if ng:
        break

print('No' if ng else 'Yes')

Submission status: Time Limit Exceeded

Solution code:
from collections import deque
# 初期入力
import sys
input = sys.stdin.readline
N,M = (int(x) for x in input().split())
max_x =123456
x =[max_x]*2*10**5
L=[0]*M
R=[0]*M
D=[0]*M
connection ={i:set() for i in range(1,N+1)}
if M ==0:
    print("Yes")
    exit()
else:
    for i in range(M):
        l,r,d = (int(x) for x in input().split())
        L[i] =l
        R[i] =r
        D[i] =d
        connection[l].add(r)
        connection[r].add(l)
    
#1つ仮定して、矛盾するかみる
#x[L[0]] =1
ans ="Yes"
already =set()
yet =set(connection.keys())
#yet =deque(L)
while yet:
    temp =yet.pop()
    x[temp] =1
    for i in range(M):
        if x[L[i]] != max_x and x[R[i]] != max_x:
            if x[R[i]] - x[L[i]] !=D[i]:
                ans ="No"
                break
            else:
                continue
        elif x[L[i]] == max_x and x[R[i]] == max_x:
            continue
        elif x[L[i]] != max_x:
            x[R[i]] =D[i] +x[L[i]]
            already.add(R[i])
            continue
        elif x[R[i]] != max_x:
            x[L[i]] =-D[i] +x[R[i]]
            already.add(L[i])
    yet -=already
print(ans)

Submission status: Time Limit Exceeded

Solution code:
# Union Find 木
from sys import setrecursionlimit


def find(parent, i):
    t = parent[i]
    if t < 0:
        return i
    t = find(parent, t)
    parent[i] = t
    return t


def unite(parent, i, j):
    i = find(parent, i)
    j = find(parent, j)
    if i == j:
        return
    if i < j:
        parent[i] += parent[j]
        parent[j] = i
    else:
        parent[j] += parent[i]
        parent[i] = j


setrecursionlimit(10 ** 6)

N, M = map(int, input().split())
LRD = [tuple(map(int, input().split())) for _ in range(M)]
LRD.sort()

parent = [-1] * (N + 1)
for L, R, D in LRD:
    unite(parent, L, R)

d = {}
for i in range(1, N + 1):
    if parent[i] < 0:
        d[i] = 0

q = []
for L, R, D in LRD:
    if L > R:
        L, R = R, L
        D = -D
    q.append((L, R, D))

while q:
    nq = []
    for L, R, D in q:
        if L in d and R in d:
            if d[L] + D != d[R]:
                print('No')
                exit()
        elif L in d:
            d[R] = d[L] + D
        elif R in d:
            d[L] = d[R] - D
        else:
            nq.append((L, R, D))
    q = nq
print('Yes')

Submission status: Time Limit Exceeded

Solution code:
#!/usr/bin/env python3

import sys
# import time
# import math
# import numpy as np
# import scipy.sparse.csgraph as cs            # csgraph_from_dense(ndarray, null_value=inf), bellman_ford(G, return_predecessors=True), dijkstra, floyd_warshall
# import random                                # random, uniform, randint, randrange, shuffle, sample
# import string                                # ascii_lowercase, ascii_uppercase, ascii_letters, digits, hexdigits
# import re                                    # re.compile(pattern) => ptn obj; p.search(s), p.match(s), p.finditer(s) => match obj; p.sub(after, s)
# from bisect import bisect_left, bisect_right # bisect_left(a, x, lo=0, hi=len(a)) returns i such that all(val<x for val in a[lo:i]) and all(val>-=x for val in a[i:hi]).
from collections import deque                # deque class. deque(L): dq.append(x), dq.appendleft(x), dq.pop(), dq.popleft(), dq.rotate()
# from collections import defaultdict          # subclass of dict. defaultdict(facroty)
# from collections import Counter              # subclass of dict. Counter(iter): c.elements(), c.most_common(n), c.subtract(iter)
# from datetime import date, datetime          # date.today(), date(year,month,day) => date obj; datetime.now(), datetime(year,month,day,hour,second,microsecond) => datetime obj; subtraction => timedelta obj
# from datetime.datetime import strptime       # strptime('2019/01/01 10:05:20', '%Y/%m/%d/ %H:%M:%S') returns datetime obj
# from datetime import timedelta               # td.days, td.seconds, td.microseconds, td.total_seconds(). abs function is also available.
# from copy import copy, deepcopy              # use deepcopy to copy multi-dimentional matrix without reference
# from functools import reduce                 # reduce(f, iter[, init])
# from functools import lru_cache              # @lrucache ...arguments of functions should be able to be keys of dict (e.g. list is not allowed)
# from heapq import heapify, heappush, heappop # built-in list. heapify(L) changes list in-place to min-heap in O(n), heappush(heapL, x) and heappop(heapL) in O(lgn).
# from heapq import nlargest, nsmallest        # nlargest(n, iter[, key]) returns k-largest-list in O(n+klgn).
# from itertools import count, cycle, repeat   # count(start[,step]), cycle(iter), repeat(elm[,n])
# from itertools import groupby                # [(k, list(g)) for k, g in groupby('000112')] returns [('0',['0','0','0']), ('1',['1','1']), ('2',['2'])]
# from itertools import starmap                # starmap(pow, [[2,5], [3,2]]) returns [32, 9]
# from itertools import product, permutations  # product(iter, repeat=n), permutations(iter[,r])
# from itertools import combinations, combinations_with_replacement
# from itertools import accumulate             # accumulate(iter[, f])
from operator import itemgetter              # itemgetter(1), itemgetter('key')
# from fractions import gcd                    # for Python 3.4 (previous contest @AtCoder)



def main():
    mod = 1000000007                # 10^9+7
    inf = float('inf')              # sys.float_info.max = 1.79...e+308
    # inf = 2 ** 64 - 1             # (for fast JIT compile in PyPy) 1.84...e+19
    sys.setrecursionlimit(10**6)    # 1000 -> 1000000
    def input(): return sys.stdin.readline().rstrip()
    def ii():    return int(input())
    def mi():    return map(int, input().split())
    def mi_0():  return map(lambda x: int(x)-1, input().split())
    def lmi():   return list(map(int, input().split()))
    def lmi_0(): return list(map(lambda x: int(x)-1, input().split()))
    def li():    return list(input())


    class UnionFindTree:
        def __init__(self, num_of_elm):
            '''
            0 ... num_of_elem - 1 まで数字で表される (0-index) グループを管理する union find tree を作成する (O(n))
            '''
            self.n = num_of_elm
            self.table = [i for i in range(self.n)]    # table[ind] は ind の親の index を表す。ind == table[ind] の時そのグループの root である。
            self.rank = [0] * self.n    # root となる ind について rank[ind] はその木の深さを表す。それ以外の ind については意味を持たない。
            self.group_size = [1] * self.n    # root となる ind について group_size[ind] はそのグループに属するメンバの個数を表す。それ以外の ind については意味を持たない。
        
        def _find_set(self, x):
            '''
            x の属するグループ番号を O(α(n)) で求める
            '''
            parent = self.table[x]
            if x == parent:
                return x
            else:
                root = self._find_set(parent)
                # 経路圧縮
                self.table[x] = root
                return root
        
        def is_same(self, x, y):
            '''
            x と y が同じグループに属するか O(α(n)) で判定する
            '''
            return self._find_set(x) == self._find_set(y)
    
        def union(self, x, y):
            '''
            x と y の属するグループを O(α(n)) で統合する
            '''
            shallow_root = self._find_set(x)
            deep_root = self._find_set(y)
            if self.rank[shallow_root] > self.rank[deep_root]:
                shallow_root, deep_root = deep_root, shallow_root
            # そもそも同一グループだった時
            if shallow_root == deep_root:
                return False
            # グループが異なるので union
            else:
                self.table[shallow_root] = deep_root
                self.group_size[deep_root] += self.group_size[shallow_root]
                # 深さが等しかったときはつけ加えられた側の rank をインクリメントする
                if self.rank[shallow_root] == self.rank[deep_root]:
                    self.rank[deep_root] += 1
                return True
    
        def akin_num(self, x):
            '''
            x の属するグループのサイズを O(1) で計算する
            '''
            x_root = self._find_set(x)
            return self.group_size[x_root]
    
        def print_group_id(self):
            print([self._find_set(x) for x in self.table])

    
    def bfs_and_check_no_contradict(start, info):
        visited = [False] * n
        dist_list = [None] * n
        dist_list[start] = 0
        q = deque([start])
        while q:
            u = q.popleft()
            if not visited[u]:
                visited[u] = True
                for v, dist in info[u]:
                    if dist_list[v] is None:
                        dist_list[v] = dist_list[u] + dist
                    elif dist_list[v] != dist_list[u] + dist:
                        return False
                for v, dist in info[u]:
                    if not visited[v]:
                        q.append(v)
        return True
            


    def no_contradict_p(info):
        uf = UnionFindTree(n)
        # group_num = n
        for l in range(n):
            for r, _ in info[l]:
                uf.union(l, r)
        #         if uf.union(l, r):
        #             group_num -= 1
        # print(group_num)
        
        for ind, g in enumerate(uf.table):
            # print(ind)
            if ind == g:
                if not bfs_and_check_no_contradict(g, info):
                    return False
        # # 距離関係の矛盾は今のところなかった。あとは座標のレンジがおさまるかチェック
        # for g, d in point_dict.items():
        #     if max(d.values()) -  min(d.values()) > 10**9:    # どうスライド移動しても入らない
        #         return False
        return True

    
    n, m = mi()
    info = [[] for _ in range(n)]
    for _ in range(m):
        l, r, dist = mi_0()
        dist += 1
        info[l].append((r, dist))
        info[r].append((l, -dist))
    
    print('Yes') if no_contradict_p(info) else print('No')



if __name__ == "__main__":
    main()

Submission status: Time Limit Exceeded

Solution code:
#!/usr/bin/env python3

import sys
# import time
# import math
# import numpy as np
# import scipy.sparse.csgraph as cs            # csgraph_from_dense(ndarray, null_value=inf), bellman_ford(G, return_predecessors=True), dijkstra, floyd_warshall
# import random                                # random, uniform, randint, randrange, shuffle, sample
# import string                                # ascii_lowercase, ascii_uppercase, ascii_letters, digits, hexdigits
# import re                                    # re.compile(pattern) => ptn obj; p.search(s), p.match(s), p.finditer(s) => match obj; p.sub(after, s)
# from bisect import bisect_left, bisect_right # bisect_left(a, x, lo=0, hi=len(a)) returns i such that all(val<x for val in a[lo:i]) and all(val>-=x for val in a[i:hi]).
# from collections import deque                # deque class. deque(L): dq.append(x), dq.appendleft(x), dq.pop(), dq.popleft(), dq.rotate()
# from collections import defaultdict          # subclass of dict. defaultdict(facroty)
# from collections import Counter              # subclass of dict. Counter(iter): c.elements(), c.most_common(n), c.subtract(iter)
# from datetime import date, datetime          # date.today(), date(year,month,day) => date obj; datetime.now(), datetime(year,month,day,hour,second,microsecond) => datetime obj; subtraction => timedelta obj
# from datetime.datetime import strptime       # strptime('2019/01/01 10:05:20', '%Y/%m/%d/ %H:%M:%S') returns datetime obj
# from datetime import timedelta               # td.days, td.seconds, td.microseconds, td.total_seconds(). abs function is also available.
# from copy import copy, deepcopy              # use deepcopy to copy multi-dimentional matrix without reference
# from functools import reduce                 # reduce(f, iter[, init])
# from functools import lru_cache              # @lrucache ...arguments of functions should be able to be keys of dict (e.g. list is not allowed)
# from heapq import heapify, heappush, heappop # built-in list. heapify(L) changes list in-place to min-heap in O(n), heappush(heapL, x) and heappop(heapL) in O(lgn).
# from heapq import nlargest, nsmallest        # nlargest(n, iter[, key]) returns k-largest-list in O(n+klgn).
# from itertools import count, cycle, repeat   # count(start[,step]), cycle(iter), repeat(elm[,n])
# from itertools import groupby                # [(k, list(g)) for k, g in groupby('000112')] returns [('0',['0','0','0']), ('1',['1','1']), ('2',['2'])]
# from itertools import starmap                # starmap(pow, [[2,5], [3,2]]) returns [32, 9]
# from itertools import product, permutations  # product(iter, repeat=n), permutations(iter[,r])
# from itertools import combinations, combinations_with_replacement
# from itertools import accumulate             # accumulate(iter[, f])
from operator import itemgetter              # itemgetter(1), itemgetter('key')
# from fractions import gcd                    # for Python 3.4 (previous contest @AtCoder)



def main():
    mod = 1000000007                # 10^9+7
    inf = float('inf')              # sys.float_info.max = 1.79...e+308
    # inf = 2 ** 64 - 1             # (for fast JIT compile in PyPy) 1.84...e+19
    sys.setrecursionlimit(10**6)    # 1000 -> 1000000
    def input(): return sys.stdin.readline().rstrip()
    def ii():    return int(input())
    def mi():    return map(int, input().split())
    def mi_0():  return map(lambda x: int(x)-1, input().split())
    def lmi():   return list(map(int, input().split()))
    def lmi_0(): return list(map(lambda x: int(x)-1, input().split()))
    def li():    return list(input())


    class UnionFindTree:
        def __init__(self, num_of_elm):
            '''
            0 ... num_of_elem - 1 まで数字で表される (0-index) グループを管理する union find tree を作成する (O(n))
            '''
            self.n = num_of_elm
            self.table = [i for i in range(self.n)]    # table[ind] は ind の親の index を表す。ind == table[ind] の時そのグループの root である。
            self.rank = [0] * self.n    # root となる ind について rank[ind] はその木の深さを表す。それ以外の ind については意味を持たない。
            self.group_size = [1] * self.n    # root となる ind について group_size[ind] はそのグループに属するメンバの個数を表す。それ以外の ind については意味を持たない。
        
        def _find_set(self, x):
            '''
            x の属するグループ番号を O(α(n)) で求める
            '''
            parent = self.table[x]
            if x == parent:
                return x
            else:
                root = self._find_set(parent)
                # 経路圧縮
                self.table[x] = root
                return root
        
        def is_same(self, x, y):
            '''
            x と y が同じグループに属するか O(α(n)) で判定する
            '''
            return self._find_set(x) == self._find_set(y)
    
        def union(self, x, y):
            '''
            x と y の属するグループを O(α(n)) で統合する
            '''
            shallow_root = self._find_set(x)
            deep_root = self._find_set(y)
            if self.rank[shallow_root] > self.rank[deep_root]:
                shallow_root, deep_root = deep_root, shallow_root
            # そもそも同一グループだった時
            if shallow_root == deep_root:
                return False
            # グループが異なるので union
            else:
                self.table[shallow_root] = deep_root
                self.group_size[deep_root] += self.group_size[shallow_root]
                # 深さが等しかったときはつけ加えられた側の rank をインクリメントする
                if self.rank[shallow_root] == self.rank[deep_root]:
                    self.rank[deep_root] += 1
                return True
    
        def akin_num(self, x):
            '''
            x の属するグループのサイズを O(1) で計算する
            '''
            x_root = self._find_set(x)
            return self.group_size[x_root]
    
        def print_group_id(self):
            print([self._find_set(x) for x in self.table])

    
    def dfs_and_check_no_contradict(start, info):
        visited = [False] * n
        dist_list = [None] * n
        visited[start] = True
        dist_list[start] = 0
        stack = [start]
        while stack:
            u = stack[-1]
            for v, dist in info[u]:
                if dist_list[v] is None:
                    dist_list[v] = dist_list[u] + dist
                elif dist_list[v] != dist_list[u] + dist:
                    return False
            for v, dist in info[u]:
                if not visited[v]:
                    visited[v] = True
                    stack.append(v)
                    break
            else:
                stack.pop()
        return True
            


    def no_contradict_p(info):
        uf = UnionFindTree(n)
        for l in range(n):
            for r, _ in info[l]:
                uf.union(l, r)
        
        for ind, g in enumerate(uf.table):
            if ind == g:
                if not dfs_and_check_no_contradict(g, info):
                    return False
        # # 距離関係の矛盾は今のところなかった。あとは座標のレンジがおさまるかチェック
        # for g, d in point_dict.items():
        #     if max(d.values()) -  min(d.values()) > 10**9:    # どうスライド移動しても入らない
        #         return False
        return True

    
    n, m = mi()
    info = [[] for _ in range(n)]
    for _ in range(m):
        l, r, dist = mi_0()
        dist += 1
        info[l].append((r, dist))
        info[r].append((l, -dist))
    
    print('Yes') if no_contradict_p(info) else print('No')



if __name__ == "__main__":
    main()