Problem p03108 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>

using namespace std;

#define lli long long int
#define REP(i, n) for (int i = 0; i < n; i++)
#define REP2(i, n) for (int i = 1; i <= n; i++)
#define DEBUG 0

typedef struct UnionFind {
  vector<lli> par; // par[i]:iの親番号 par[3] = 2 : 3の親が2
  vector<lli>
      size; // size[i]:iの大きさ 自分のみのときは1,根っこにsizeを持たせる*/

  UnionFind(int N) { /*最初はすべてが根であると初期化*/
    REP(i, N) {
      par.push_back(i);
      size.push_back(1);
    }
  }

  lli root(lli x) { /*データxが属する木の根を再起で得る root(x) = {xの木の根}}*/
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]);
  }

  void unite(lli x, lli y) { /*xとyの併合*/
    lli rx = root(x);
    lli ry = root(y);
    if (rx == ry)
      return;
    par[rx] = ry; /*xとyの根が同じじゃない: xの根をrxをyの根ryに変更する */
    lli resize = size[rx] + size[ry];
    size[rx] = resize;
    size[ry] = resize;
  }

  bool same(lli x, lli y) {
    lli rx = root(x);
    lli ry = root(y);
    return rx == ry;
  }

  lli getSize(lli x) {
    lli rx = root(x);
    return size[rx];
  }
};

int main() {

  lli n, m;
  cin >> n >> m;
  vector<lli> a(m), b(m);
  UnionFind uf(n);

  REP(i, m) {
    lli ta, tb;
    cin >> ta >> tb;
    ta--;
    tb--;
    a[i] = ta;
    b[i] = tb;
  }

  vector<lli> ans(n, 0);
  ans[m - 1] = n * (n - 1) / 2;

  for (lli i = m - 1; i > 0; i--) {
    if (uf.same(a[i], b[i])) {
      ans[i - 1] = ans[i];
    } else {
      ans[i - 1] = ans[i] - uf.getSize(a[i]) * uf.getSize(b[i]);
      uf.unite(a[i], b[i]);
    }
  }
  REP(i, m) { cout << ans[i] << endl; }

  return 0;
}

Fixed submission:
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>

using namespace std;

#define lli long long int
#define REP(i, n) for (int i = 0; i < n; i++)
#define REP2(i, n) for (int i = 1; i <= n; i++)
#define DEBUG 0

typedef struct UnionFind {
  vector<lli> par; // par[i]:iの親番号 par[3] = 2 : 3の親が2
  vector<lli>
      size; // size[i]:iの大きさ 自分のみのときは1,根っこにsizeを持たせる*/

  UnionFind(int N) { /*最初はすべてが根であると初期化*/
    REP(i, N) {
      par.push_back(i);
      size.push_back(1);
    }
  }

  lli root(lli x) { /*データxが属する木の根を再起で得る root(x) = {xの木の根}}*/
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]);
  }

  void unite(lli x, lli y) { /*xとyの併合*/
    lli rx = root(x);
    lli ry = root(y);
    if (rx == ry)
      return;
    par[rx] = ry; /*xとyの根が同じじゃない: xの根をrxをyの根ryに変更する */
    lli resize = size[rx] + size[ry];
    size[rx] = resize;
    size[ry] = resize;
  }

  bool same(lli x, lli y) {
    lli rx = root(x);
    lli ry = root(y);
    return rx == ry;
  }

  lli getSize(lli x) {
    lli rx = root(x);
    return size[rx];
  }
};

int main() {

  lli n, m;
  cin >> n >> m;
  vector<lli> a(m), b(m);
  UnionFind uf(n);

  REP(i, m) {
    lli ta, tb;
    cin >> ta >> tb;
    ta--;
    tb--;
    a[i] = ta;
    b[i] = tb;
  }

  vector<lli> ans(m, 0);
  ans[m - 1] = n * (n - 1) / 2;

  for (lli i = m - 1; i > 0; i--) {
    if (uf.same(a[i], b[i])) {
      ans[i - 1] = ans[i];
    } else {
      ans[i - 1] = ans[i] - uf.getSize(a[i]) * uf.getSize(b[i]);
      uf.unite(a[i], b[i]);
    }
  }
  REP(i, m) { cout << ans[i] << endl; }

  return 0;
}