Problem p03108 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
#define SORT(x) sort((x).begin(), (x).end())
#define ALL(x) (x).begin(), (x).end()
#define rep(i, n) for (int i = 0; i < n; i++)
#define reps(i, m, n) for (int i = m; i < n; i++)
#define repr(i, m, n) for (int i = m; i >= n; i--)
#define db(x) cout << #x << "=" << x << endl
template <class T> bool maxi(T &a, const T &b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> bool mini(T &a, const T &b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}
#define y0 y3487465 // y1 j0 j1
#define INF2 4000000000000000037
#define INF 1000000007
#define PI (acos(-1))
#define MOD 1000000007
#define EPS 1e(-9);
using namespace std;
typedef long long ll;

struct UnionFind {
  vector<int> par; // 親ノード rootで取得すること
  vector<int> rank;
  vector<ll> nodes;

  UnionFind(int n) {
    par.resize(n);
    rank.resize(n);
    nodes.resize(n);
    rep(i, n) {
      par[i] = i, rank[i] = 0;
      nodes[i] = 1;
    }
  }

  int root(int x) { // ノードの根を返す
    if (par[x] == x)
      return x; // 親が自分なら自分を返す
    else {
      int r = root(par[x]); // 根まで遡りながら経路圧縮
      return par[x] = r;
    }
  }
  bool issame(int x, int y) { return root(x) == root(y); }
  bool merge(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (rank[x] < rank[y])
      swap(x, y);
    if (rank[x] == rank[y])
      ++rank[x];
    par[y] = x; // ランクの小さい方に接続
    return true;
  }
  ll query(int x, int y) {
    if (issame(x, y))
      return 0;
    ll sum = nodes[root(x)] + nodes[root(y)];
    ll res = nodes[root(x)] * nodes[root(y)];
    merge(x, y);
    nodes[root(x)] = sum;
    return res;
  }
};

void Main() {

  int N, M;
  cin >> N >> M;

  int A[N], B[N];

  UnionFind uf(N);

  rep(i, M) {
    cin >> A[i] >> B[i];
    --A[i];
    --B[i];
  }

  ll ans[M + 1];
  ll sum = 0;
  repr(i, M - 1, 0) { ans[i] = uf.query(A[i], B[i]); }

  rep(i, M) {
    cout << ans[i] << "\n";
    ans[i + 1] += ans[i];
  }
}

//-----------------------------------
int main() {
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  cout << fixed << setprecision(15);
  Main();
}
//-----------------------------------


Fixed submission:
#include <bits/stdc++.h>
#define SORT(x) sort((x).begin(), (x).end())
#define ALL(x) (x).begin(), (x).end()
#define rep(i, n) for (int i = 0; i < n; i++)
#define reps(i, m, n) for (int i = m; i < n; i++)
#define repr(i, m, n) for (int i = m; i >= n; i--)
#define db(x) cout << #x << "=" << x << endl
template <class T> bool maxi(T &a, const T &b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> bool mini(T &a, const T &b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}
#define y0 y3487465 // y1 j0 j1
#define INF2 4000000000000000037
#define INF 1000000007
#define PI (acos(-1))
#define MOD 1000000007
#define EPS 1e(-9);
using namespace std;
typedef long long ll;

struct UnionFind {
  vector<int> par; // 親ノード rootで取得すること
  vector<int> rank;
  vector<ll> nodes;

  UnionFind(int n) {
    par.resize(n);
    rank.resize(n);
    nodes.resize(n);
    rep(i, n) {
      par[i] = i, rank[i] = 0;
      nodes[i] = 1;
    }
  }

  int root(int x) { // ノードの根を返す
    if (par[x] == x)
      return x; // 親が自分なら自分を返す
    else {
      int r = root(par[x]); // 根まで遡りながら経路圧縮
      return par[x] = r;
    }
  }
  bool issame(int x, int y) { return root(x) == root(y); }
  bool merge(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    if (rank[x] < rank[y])
      swap(x, y);
    if (rank[x] == rank[y])
      ++rank[x];
    par[y] = x; // ランクの小さい方に接続
    return true;
  }
  ll query(int x, int y) {
    if (issame(x, y))
      return 0;
    ll sum = nodes[root(x)] + nodes[root(y)];
    ll res = nodes[root(x)] * nodes[root(y)];
    merge(x, y);
    nodes[root(x)] = sum;
    return res;
  }
};

void Main() {

  int N, M;
  cin >> N >> M;

  int A[M], B[M];

  UnionFind uf(N);

  rep(i, M) {
    cin >> A[i] >> B[i];
    --A[i];
    --B[i];
  }

  ll ans[M + 1];
  ll sum = 0;
  repr(i, M - 1, 0) { ans[i] = uf.query(A[i], B[i]); }

  rep(i, M) {
    cout << ans[i] << "\n";
    ans[i + 1] += ans[i];
  }
}

//-----------------------------------
int main() {
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  cout << fixed << setprecision(15);
  Main();
}
//-----------------------------------