#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <utility>
#include <iomanip>
#include <algorithm>
#include <functional>
#include <unordered_map>
using namespace std;

#define REP(i, s) for (int i = 0; i < s; ++i)
#define ALL(v) (v.begin(), v.end())
#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl
#define EACH(i, s) for (__typeof__((s).begin()) i = (s).begin(); i != (s).end(); ++i)

template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T> ostream& operator << (ostream &s, set<T> P)
{ EACH(it, P) { s << "<" << *it << "> "; } return s << endl; }
template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)
{ EACH(it, P) { s << "<" << it->first << "->" << it->second << "> "; } return s << endl; }


typedef int VAL;
const int MAX_UF = 110000;
const VAL SUM_UNITY = 0;

struct UnionFind {
  int size_uf;
  int par[MAX_UF];
  int rank[MAX_UF];
  VAL weight[MAX_UF];
  int size_component[MAX_UF];

  UnionFind(int n = 0) {
	size_uf = n;
	for (int i = 0; i < n; ++i) par[i] = i, rank[i] = 0, weight[i] = SUM_UNITY, size_component[i] = 1;
  }
  
  void init(int n) {
	size_uf = n;
	for (int i = 0; i < n; ++i) par[i] = i, rank[i] = 0, weight[i] = SUM_UNITY, size_component[i] = 1;
  }
  
  int root(int x) {
	if (par[x] == x) {
	  return x;
	}
	else {
	  int r = root(par[x]);
	  weight[x] += weight[par[x]];
	  return par[x] = r;
	}
  }

  int size(int x) {
	return size_component[root(x)];
  }

  VAL calc_weight(int x) {
	root(x);
	return weight[x];
  }
  
  bool issame(int x, int y) {
	return root(x) == root(y);
  }

  bool merge(int x, int y, VAL w) {
	w += calc_weight(x);
	w -= calc_weight(y);
	
	x = root(x);
	y = root(y);
	int sx = size_component[x], sy = size_component[y];
	if (x == y) return false;
	if (rank[x] < rank[y]) swap(x, y), w = -w;
	if (rank[x] == rank[y]) ++rank[x];
	par[y] = x;
	weight[y] = w;
	size_component[x] = sx + sy;
	return true;
  }

  VAL diff(int x, int y) {
	return calc_weight(y) - calc_weight(x);
  }

  friend ostream& operator << (ostream& s, UnionFind uf) {
	map<int, vector<int> > res;
	for (int i = 0; i < uf.size_uf; ++i) {
	  int r = uf.root(i);
	  res[r].push_back(i);
	}
	for (map<int, vector<int> >::iterator it = res.begin(); it != res.end(); ++it) {
	  s << endl;
	  for (int j = 0; j < (int)it->second.size(); ++j) {
		s << it->second[j] << "(" << uf.calc_weight(it->second[j]) << "), ";
	  }
	}
	return s << endl;
  }
} uf;



int N, M;
int main() {
  cin >> N >> M;
  uf.init(N);
  for (int i = 0; i < M; ++i) {
	int l, r, d;
	cin >> l >> r >> d;
	--l, --r;
	if (uf.issame(l, r)) {
	  int diff = uf.diff(l, r);
	  if (diff != d) {
		puts("No");
		return 0;
	  }
	}
	else {
	  uf.merge(l, r, d);
	}

	//COUT(uf);
  }
  puts("Yes");
}




Measured memory_bytes: 1792