#include <cassert>
#include <utility>

template <class Group, template <class> class Container>
class potentialized_union_find {
protected:
	class node_type;

public:
	using value_structure = Group;
	using value_type = typename value_structure::value_type;
	using container_type = Container<node_type>;
	using size_type = typename container_type::size_type;

protected:
	class node_type {
	public:
		typename potentialized_union_find::size_type parent;
		typename potentialized_union_find::value_type value;
		typename potentialized_union_find::size_type size;
	};

	container_type tree;

private:
	value_type potential(size_type x) {
		value_type ret = value_structure::identity();
		while (tree[x].parent != x) {
			tree[x].value =
				value_structure::operation(tree[tree[x].parent].value, tree[x].value);
			ret = value_structure::operation(tree[x].value, ret);
			x = tree[x].parent = tree[tree[x].parent].parent;
		}
		return ::std::move(ret);
	}

public:
	potentialized_union_find() : tree() {}
	explicit potentialized_union_find(const size_type size)
		: tree(size, { 0, value_structure::identity(), 1 }) {
		for (size_type i = 0; i < size; ++i)
			tree[i].parent = i;
	}

	bool empty() const { return tree.empty(); }
	size_type size() const { return tree.size(); }

	size_type find(size_type x) {
		assert(x < size());
		while (tree[x].parent != x) {
			tree[x].value =
				value_structure::operation(tree[tree[x].parent].value, tree[x].value);
			x = tree[x].parent = tree[tree[x].parent].parent;
		}
		return x;
	}
	value_type diff(const size_type x, const size_type y) {
		assert(x < size());
		assert(y < size());
		assert(same(x, y));
		return value_structure::operation(value_structure::inverse(potential(x)),
			potential(y));
	}
	bool same(const size_type x, const size_type y) {
		assert(x < size());
		assert(y < size());
		return find(x) == find(y);
	}
	size_type size(const size_type x) {
		assert(x < size());
		return tree[find(x)].size;
	}

	::std::pair<size_type, size_type> unite(size_type x, size_type y,
		value_type d) {
		assert(x < size());
		assert(y < size());
		d = value_structure::operation(
			value_structure::operation(potential(x), ::std::move(d)),
			value_structure::inverse(potential(y)));
		x = find(x);
		y = find(y);
		if (x != y) {
			if (tree[x].size < tree[y].size) {
				::std::swap(x, y);
				d = value_structure::inverse(::std::move(d));
			}
			tree[x].size += tree[y].size;
			tree[y].parent = x;
			tree[y].value = ::std::move(d);
		}
		return { x, y };
	}
};

template <class T> class plus_abelian {
public:
	using value_type = T;
	static value_type operation(const value_type &x, const value_type &y) {
		return x + y;
	}
	static value_type identity() { return value_type(0); }
	static value_type inverse(const value_type &x) { return -x; }
	static value_type reverse(const value_type &x) { return x; }
};

#include<iostream>
#include<tuple>
#include<vector>
template<class T>
using vec_alias = ::std::vector<T>;

int main() {
	int n, m;
	::std::cin >> n >> m;
	potentialized_union_find<plus_abelian<int>, vec_alias> puf(n);

	while (m--) {
		int l, r, d;
		::std::cin >> l >> r >> d;
		--l;
		--r;

		if (puf.same(l, r)) {
			if (puf.diff(l, r) != d) {
				::std::cout << "No" << ::std::endl;
				return 0;
			}
		}
		else {
			puf.unite(l, r, d);
		}
	}

	::std::cout << "Yes" << ::std::endl;

	return 0;
}


Measured memory_bytes: 2688