#!/usr/bin/env python3
import sys
from collections import defaultdict, deque

YES = "Yes"  # type: str
NO = "No"  # type: str

def solve(N: int, M: int, L: "List[int]", R: "List[int]", D: "List[int]"):
    visited = 0
    pos = [None] * N
    adj = [set() for _ in range(N)]

    for l, r, d in zip(L, R, D):
        adj[l].add((r, d))
        adj[r].add((l, -d))
    
    for i in range(N):
        if (visited >> i) % 2 == 1:
            continue
        pos[i] = 0
        Q = deque([i], M)
        while len(Q) > 0:
            u = Q.popleft()
            visited |= 1 << u
            for v, d in adj[u]:
                if pos[v] is None:
                    pos[v] = pos[u] + d
                elif pos[v] != pos[u] + d:
                    print(NO)
                    return

                if (visited >> v) % 2 == 1:
                    continue
                Q.append(v)
    print(YES)
    return


# Generated by 1.1.4 https://github.com/kyuridenamida/atcoder-tools  (tips: You use the default template now. You can remove this line by using your custom template)
def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    M = int(next(tokens))  # type: int
    L = [int()] * (M)  # type: "List[int]" 
    R = [int()] * (M)  # type: "List[int]" 
    D = [int()] * (M)  # type: "List[int]" 
    for i in range(M):
        L[i] = int(next(tokens)) - 1
        R[i] = int(next(tokens)) - 1
        D[i] = int(next(tokens))
    solve(N, M, L, R, D)

if __name__ == '__main__':
    main()
