Problem p03108 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
#define all(x) (x).begin(), (x).end()
#define pll pair<ll, ll>
#define rep(i, n) for (int i = 0; i < n; i++)
#define sz(x) ((ll)(x).size())
#define pb push_back
#define mp make_pair
#define bit(n) (1LL << (n))
#define F first
#define S second
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
const ll INF = 1LL << 60;
const ll mod = (int)1e9 + 7;

class UnionFind {
public:
  vector<ll> par; // 各元の親を表す配列
  vector<ll> siz; // 素集合のサイズを表す配列(1 で初期化)

  // Constructor
  UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }
  void init(ll sz_) {
    siz.assign(sz_, 1LL); // assign: 再代入
    par.resize(sz_);      // resize: 再確保
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }

  // Member Function
  // Find
  ll root(ll x) { // 根の検索
    while (par[x] != x) {
      x = par[x] = par[par[x]]; // x の親の親を x の親とする
    }
    return x;
  }

  // Union(Unite, Merge)
  bool merge(ll x, ll y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    // merge technique（データ構造をマージするテク．小を大にくっつける）
    if (siz[x] < siz[y])
      swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool issame(ll x, ll y) { // 連結判定
    return root(x) == root(y);
  }

  ll size(ll x) { // 素集合のサイズ
    return siz[root(x)];
  }
};

int main() {
  // ll N; cin >> N;
  ll N, M;
  cin >> N >> M;
  // string S; cin >> S;
  // ll H,W; cin >> H >> W;
  vector<pll> pe(M);
  rep(i, M) {
    int a, b;
    cin >> a >> b;
    pe[i] = mp(a, b);
  }
  vector<ll> ans(M);
  ans[M - 1] = N * (N - 1) / 2;
  UnionFind tree(N);
  for (int i = M - 1; i > 0; i--) {
    int a, b;
    a = pe[i].F;
    b = pe[i].S;
    if (tree.issame(a, b))
      ans[i - 1] = ans[i];
    else {
      ans[i - 1] = ans[i] - tree.size(a) * tree.size(b);
      tree.merge(a, b);
    }
  }
  rep(i, M) { cout << ans[i] << endl; }
}

/*



 */


Fixed submission:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
#define all(x) (x).begin(), (x).end()
#define pll pair<ll, ll>
#define rep(i, n) for (int i = 0; i < n; i++)
#define sz(x) ((ll)(x).size())
#define pb push_back
#define mp make_pair
#define bit(n) (1LL << (n))
#define F first
#define S second
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
const ll INF = 1LL << 60;
const ll mod = (int)1e9 + 7;

class UnionFind {
public:
  vector<ll> par; // 各元の親を表す配列
  vector<ll> siz; // 素集合のサイズを表す配列(1 で初期化)

  // Constructor
  UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }
  void init(ll sz_) {
    siz.assign(sz_, 1LL); // assign: 再代入
    par.resize(sz_);      // resize: 再確保
    for (ll i = 0; i < sz_; ++i)
      par[i] = i; // 初期では親は自分自身
  }

  // Member Function
  // Find
  ll root(ll x) { // 根の検索
    while (par[x] != x) {
      x = par[x] = par[par[x]]; // x の親の親を x の親とする
    }
    return x;
  }

  // Union(Unite, Merge)
  bool merge(ll x, ll y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return false;
    // merge technique（データ構造をマージするテク．小を大にくっつける）
    if (siz[x] < siz[y])
      swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool issame(ll x, ll y) { // 連結判定
    return root(x) == root(y);
  }

  ll size(ll x) { // 素集合のサイズ
    return siz[root(x)];
  }
};

int main() {
  // ll N; cin >> N;
  ll N, M;
  cin >> N >> M;
  // string S; cin >> S;
  // ll H,W; cin >> H >> W;
  vector<pll> pe(M);
  rep(i, M) {
    int a, b;
    cin >> a >> b;
    pe[i] = mp(a - 1, b - 1);
  }
  vector<ll> ans(M);
  ans[M - 1] = N * (N - 1) / 2;
  UnionFind tree(N);
  for (int i = M - 1; i > 0; i--) {
    int a, b;
    a = pe[i].F;
    b = pe[i].S;
    if (tree.issame(a, b))
      ans[i - 1] = ans[i];
    else {
      ans[i - 1] = ans[i] - tree.size(a) * tree.size(b);
      tree.merge(a, b);
    }
  }
  rep(i, M) { cout << ans[i] << endl; }
}

/*



 */