import qualified Data.ByteString.Lazy.Char8 as B
import Data.Maybe
import qualified Data.Vector.Unboxed.Mutable as VM
import Control.Monad
import Control.Monad.ST
import Debug.Trace

traceQ :: (Show a) => String -> a -> a
-- traceQ label a = trace (label ++ ": " ++ show a) a
traceQ _ a = a

traceZ :: String -> a -> a
-- traceZ = trace
traceZ _ a = a

bsReadInts :: B.ByteString -> [Int]
bsReadInts = map (fst . fromJust . B.readInt) . B.words

solve :: Int -> Int -> [[Int]] -> Bool
solve valN valM lrds = runST (act valN valM lrds)

act :: Int -> Int -> [[Int]] -> ST s Bool
act valN valM lrds = do
  vec <- VM.new (valN+1)
  forM_ [1 .. valN] $ \i -> VM.write vec i (i, 0)
  act1 lrds vec

act1 :: [[Int]] -> VM.MVector s (Int, Int) -> ST s Bool
act1 [] _ = return True
act1 ([l,r,d]:lrds) vec = do
  b <- step l r d vec
  if b
    then act1 lrds vec
    else return False

step :: Int -> Int -> Int -> VM.MVector s (Int, Int) -> ST s Bool
step l r d vec = do
  (grpL, coordL) <- reGroup vec l
  (grpR, coordR) <- reGroup vec r
  if grpL == grpR
    then if coordL + d == coordR
         then return True
         else return False
    else do
         VM.write vec grpR (grpL, coordL + d - coordR)
         return True

reGroup :: VM.MVector s (Int, Int) -> Int -> ST s (Int, Int)
reGroup vec x = do
  (grp, coord) <- VM.read vec x
  if x == grp then return (grp, coord)
    else do
    (newGrp, newCoord) <- reGroup vec grp
    let newXVal = (newGrp, newCoord + coord)
    VM.write vec x newXVal
    return newXVal
        

main :: IO ()
main = do
  conts <- B.getContents
  let [valN, valM] : lrds = map bsReadInts (B.lines conts)
      answer = solve valN valM lrds
  putStrLn (if answer then "Yes" else "No")
