Problem p03108 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>

#include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define all(v) v.begin(), v.end()
#define _GLIBCXX_DEBUG

using ll = long long;
using vi = vector<int>;
using vll = vector<ll>;
using vd = vector<double>;
using vvi = vector<vi>;
using vvll = vector<vll>;
using vvd = vector<vd>;
using vvvi = vector<vvi>;
using vvvll = vector<vvll>;
using vvvd = vector<vvd>;

const double pi = 3.141592653589793;

class UnionFind {
  // まとめる 判定 サイズを知る
public:
  // Aから見た親の番号を格納する。rootだったら-1*その集合のサイズ。
  vector<ll> Parent;

  // 初期化
  UnionFind(ll N) { Parent = vector<ll>(N, -1); }

  // Aのrootを調べる
  int root(ll A) {
    if (Parent[A] < 0)
      return A; // マイナスならそれはroot
    return Parent[A] = root(Parent[A]);
  }

  // rootの値をプラスに戻して返す(サイズ)
  int size(ll A) { return -Parent[root(A)]; }

  // くっつける関数
  bool connect(ll A, ll B) {
    // AとBのroot同士をくっつける
    A = root(A); // ここのAは、"rootの場所"の意味
    B = root(B);
    if (A == B)
      return false; // 既にくっついている
    if (size(A) < size(B))
      swap(A, B); // 大きい方にくっつけるために中身交換
    Parent[A] += Parent[B]; // 中身更新
    Parent[B] = A;
    return true;
  }
};

int main() {
  ll n, m;
  cin >> n >> m;
  ll now = (n * (n - 1)) / 2;
  vll ans;
  ans.push_back(now);
  UnionFind tree(n);
  vector<pair<ll, ll>> pp;
  rep(i, m) {
    ll x, y;
    cin >> x >> y;
    pp.push_back(make_pair(x, y));
  }

  for (int i = m - 1; i >= 0; i--) {
    ll x, y;
    x = pp[i].first;
    y = pp[i].second;
    ll xs = tree.size(x);
    ll ys = tree.size(y);
    if (!tree.connect(x, y)) {
      ans.push_back(now);
    } else {
      now = now - xs * ys;
      ans.push_back(now);
      // cout<<111<<endl;
    }
    // cout<<now<<endl;
  }
  for (int i = m - 1; i >= 0; i--) {
    cout << ans[i] << endl;
  }

  return 0;
}

Fixed submission:
#include <bits/stdc++.h>

#include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define all(v) v.begin(), v.end()
#define _GLIBCXX_DEBUG

using ll = long long;
using vi = vector<int>;
using vll = vector<ll>;
using vd = vector<double>;
using vvi = vector<vi>;
using vvll = vector<vll>;
using vvd = vector<vd>;
using vvvi = vector<vvi>;
using vvvll = vector<vvll>;
using vvvd = vector<vvd>;

const double pi = 3.141592653589793;

class UnionFind {
  // まとめる 判定 サイズを知る
public:
  // Aから見た親の番号を格納する。rootだったら-1*その集合のサイズ。
  vector<ll> Parent;

  // 初期化
  UnionFind(ll N) { Parent = vector<ll>(N, -1); }

  // Aのrootを調べる
  int root(ll A) {
    if (Parent[A] < 0)
      return A; // マイナスならそれはroot
    return Parent[A] = root(Parent[A]);
  }

  // rootの値をプラスに戻して返す(サイズ)
  int size(ll A) { return -Parent[root(A)]; }

  // くっつける関数
  bool connect(ll A, ll B) {
    // AとBのroot同士をくっつける
    A = root(A); // ここのAは、"rootの場所"の意味
    B = root(B);
    if (A == B)
      return false; // 既にくっついている
    if (size(A) < size(B))
      swap(A, B); // 大きい方にくっつけるために中身交換
    Parent[A] += Parent[B]; // 中身更新
    Parent[B] = A;
    return true;
  }
};

int main() {
  ll n, m;
  cin >> n >> m;
  ll now = (n * (n - 1)) / 2;
  vll ans;
  ans.push_back(now);
  UnionFind tree(n);
  vector<pair<ll, ll>> pp;
  rep(i, m) {
    ll x, y;
    cin >> x >> y;
    pp.push_back(make_pair(x, y));
  }

  for (int i = m - 1; i >= 0; i--) {
    ll x, y;
    x = pp[i].first - 1;
    y = pp[i].second - 1;
    ll xs = tree.size(x);
    ll ys = tree.size(y);
    if (!tree.connect(x, y)) {
      ans.push_back(now);
    } else {
      now = now - xs * ys;
      ans.push_back(now);
      // cout<<111<<endl;
    }
    // cout<<now<<endl;
  }
  for (int i = m - 1; i >= 0; i--) {
    cout << ans[i] << endl;
  }

  return 0;
}