Problem p03450 (C++)

Buggy submission (status: Runtime Error):
#include <cassert>
#include <cstdint>
#include <functional>
#include <tuple>
#include <vector>

template <typename Abelian> class PotentializedUnionFindTree {

public:
  using value_type = Abelian;
  using reference = value_type &;
  using const_reference = const value_type &;
  using size_type = std::uint_fast32_t;

private:
  using F = std::function<value_type(const_reference, const_reference)>;
  using G = std::function<value_type(const_reference)>;
  const F f;
  const G g;
  const value_type neutral_;
  std::vector<std::tuple<bool, size_type, value_type>> tree;

public:
  PotentializedUnionFindTree(const size_type size,
                             const_reference neutral = value_type(),
                             const F &f = std::plus<value_type>(),
                             const G &g = std::negate<value_type>())
      : f(f), g(g), neutral_(neutral),
        tree(size, std::forward_as_tuple(1, 1, neutral_)) {}
  size_type find(const size_type x) {
    assert(x < tree.size());
    if (std::get<0>(tree[x]))
      return x;
    const size_type t = std::get<1>(tree[x]);
    std::get<1>(tree[x]) = find(t);
    std::get<2>(tree[x]) = f(std::get<2>(tree[t]), std::get<2>(tree[x]));
    return std::get<1>(tree[x]);
  }
  value_type potential(const size_type x) {
    assert(x < tree.size());
    find(x);
    return std::get<2>(tree[x]);
  }
  value_type diff(const size_type x, const size_type y) {
    assert(x < tree.size());
    assert(y < tree.size());
    return f(potential(y), g(potential(x)));
  }
  bool unite(size_type x, size_type y, value_type d) {
    assert(x < tree.size());
    assert(y < tree.size());
    d = f(d, diff(y, x));
    x = find(x);
    y = find(y);
    if (x == y)
      return false;
    if (std::get<1>(tree[x]) < std::get<1>(tree[y]))
      std::swap(x, y), d = g(d);
    std::get<1>(tree[x]) += std::get<1>(tree[y]);
    tree[y] = std::forward_as_tuple(0, x, d);
    return true;
  }
  bool same(const size_type x, const size_type y) {
    assert(x < tree.size());
    assert(y < tree.size());
    return find(x) == find(y);
  }
  size_type size(const size_type x) {
    assert(x < tree.size());
    return std::get<1>(tree[find(x)]);
  }
};

#include <iostream>
int main(void) {
  int n, m;
  std::cin >> n >> m;
  PotentializedUnionFindTree<int> T(n, 0);
  while (m--) {
    int l, r, d;
    std::cin >> l >> r >> d;
    if (!T.unite(l, r, d)) {
      if (T.diff(l, r) != d) {
        std::cout << "No" << std::endl;
        return 0;
      }
    }
  }
  std::cout << "Yes" << std::endl;
  return 0;
}

Fixed submission:
#include <cassert>
#include <cstdint>
#include <functional>
#include <tuple>
#include <vector>

template <typename Abelian> class PotentializedUnionFindTree {

public:
  using value_type = Abelian;
  using reference = value_type &;
  using const_reference = const value_type &;
  using size_type = std::uint_fast32_t;

private:
  using F = std::function<value_type(const_reference, const_reference)>;
  using G = std::function<value_type(const_reference)>;
  const F f;
  const G g;
  const value_type neutral_;
  std::vector<std::tuple<bool, size_type, value_type>> tree;

public:
  PotentializedUnionFindTree(const size_type size,
                             const_reference neutral = value_type(),
                             const F &f = std::plus<value_type>(),
                             const G &g = std::negate<value_type>())
      : f(f), g(g), neutral_(neutral),
        tree(size, std::forward_as_tuple(1, 1, neutral_)) {}
  size_type find(const size_type x) {
    assert(x < tree.size());
    if (std::get<0>(tree[x]))
      return x;
    const size_type t = std::get<1>(tree[x]);
    std::get<1>(tree[x]) = find(t);
    std::get<2>(tree[x]) = f(std::get<2>(tree[t]), std::get<2>(tree[x]));
    return std::get<1>(tree[x]);
  }
  value_type potential(const size_type x) {
    assert(x < tree.size());
    find(x);
    return std::get<2>(tree[x]);
  }
  value_type diff(const size_type x, const size_type y) {
    assert(x < tree.size());
    assert(y < tree.size());
    return f(potential(y), g(potential(x)));
  }
  bool unite(size_type x, size_type y, value_type d) {
    assert(x < tree.size());
    assert(y < tree.size());
    d = f(d, diff(y, x));
    x = find(x);
    y = find(y);
    if (x == y)
      return false;
    if (std::get<1>(tree[x]) < std::get<1>(tree[y]))
      std::swap(x, y), d = g(d);
    std::get<1>(tree[x]) += std::get<1>(tree[y]);
    tree[y] = std::forward_as_tuple(0, x, d);
    return true;
  }
  bool same(const size_type x, const size_type y) {
    assert(x < tree.size());
    assert(y < tree.size());
    return find(x) == find(y);
  }
  size_type size(const size_type x) {
    assert(x < tree.size());
    return std::get<1>(tree[find(x)]);
  }
};

#include <iostream>
int main(void) {
  int n, m;
  std::cin >> n >> m;
  PotentializedUnionFindTree<int> T(n, 0);
  while (m--) {
    int l, r, d;
    std::cin >> l >> r >> d;
    --l;
    --r;
    if (!T.unite(l, r, d)) {
      if (T.diff(l, r) != d) {
        std::cout << "No" << std::endl;
        return 0;
      }
    }
  }
  std::cout << "Yes" << std::endl;
  return 0;
}