#include <iostream>
#include <vector>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <array>
#include <map>
#include <set>
#include <tuple>
#include <unordered_set>
#include <stack>
#include <cassert>

using namespace std;

template <typename N = std::size_t, typename E = std::size_t>
class SparseGraph
{
public:
    using NodeType = N;
    using EdgeType = E;
    using NeighborListType = std::unordered_set<std::size_t>;

    SparseGraph(bool undirected = true) noexcept
        : undirected_(undirected)
    {
    }

    void push_node(NodeType n) noexcept
    {
        nodes_.push_back(n);
        neighbor_list_.emplace_back();
    }

    void connect(const std::size_t from, const std::size_t to, const EdgeType edge = EdgeType()) noexcept
    {
        if (undirected_)
        {
            neighbor_list_[from].insert(to);
            neighbor_list_[to].insert(from);
            edges_[std::make_pair(std::min(from, to), std::max(from, to))] = edge;
        }
        else
        {
            neighbor_list_[from].insert(to);
            edges_[std::make_pair(from, to)] = edge;
        }
    }

    void disconnect(const std::size_t from, const std::size_t to) noexcept
    {
        if (undirected_)
        {
            neighbor_list_[from].erase(to);
            neighbor_list_[to].erase(from);
            edges_.erase(std::make_pair(std::min(from, to), std::max(from, to)));
        }
        else
        {
            neighbor_list_[from].erase(to);
            edges_.erase(std::make_pair(from, to));
        }
    }

    const NodeType& node(const std::size_t index) const noexcept
    {
        return nodes_.at(index);
    }

    const EdgeType& edge(const std::size_t from, const std::size_t to) const noexcept
    {
        if (undirected_)
        {
            auto key = std::make_pair(std::min(from, to), std::max(from, to));
            return edges_.at(key);
        }
        else
        {
            auto key = std::make_pair(from, to);
            return edges_.at(key);
        }
    }

    const NeighborListType&
    neighbor(const std::size_t index) const noexcept
    {
        return neighbor_list_[index];
    }

    std::size_t size() const noexcept
    {
        return neighbor_list_.size();
    }

private:
    using EdgeMap = std::map<std::pair<std::size_t, std::size_t>, EdgeType>;

    std::vector<NeighborListType> neighbor_list_;

    EdgeMap edges_;

    std::vector<NodeType> nodes_;

    bool undirected_;
};

template <typename GraphType>
std::vector<std::size_t> topological_order(const GraphType& graph)
{
    std::vector<std::size_t> order;
    stack<int> st;

    vector<int> hs(graph.size());

    for (int v = 0; v < graph.size(); v++)
    {
        for (int nv : graph.neighbor(v))
        {
            hs[nv]++;
        }
    }
    for (int i = 0; i < graph.size(); i++)
    {
        if (hs[i] == 0)
        {
            st.push(i);
        }
    }

    vector<int> finished(graph.size(), false);

    while (!st.empty())
    {
        const int v = st.top();
        st.pop();
        order.push_back(v);
        finished[v] = true;

        for (int nv : graph.neighbor(v))
        {
            hs[nv]--;
            if (hs[nv] == 0 && !finished[nv])
            {
                st.push(nv);
            }
        }
    }

    return order;
}

int main()
{
    int n, m;
    cin >> n >> m;

    SparseGraph<> graph(false);
    for (int i = 0; i < n ;i ++)
    {
        graph.push_node(i);
    }

    for (int i = 0; i < m; i++)
    {
        int l, r, d;
        cin >> l >> r >> d;
        graph.connect(l - 1, r - 1, d);
    }

    auto order = topological_order<>(graph);

    if (order.size() < n)
    {
        cout << "No" << endl;
        return 0;
    }

    vector<int> position(n, -1);

    bool success = true;

    for (auto node : order)
    {
        for (auto next : graph.neighbor(node))
        {
            auto d = graph.edge(node, next);

            if (position[node] == -1)
            {
                position[node] = 0;
            }
            if (position[next] == -1)
            {
                position[next] = position[node] + d;
            }
            if (position[next] - position[node] != d)
            {
                success = false;
                break;
            }
        }
    }

    cout << (success ? "Yes" : "No") << endl;
}

Measured memory_bytes: 32812