Problem p03855 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <bits/stdc++.h>
using namespace std;
using ll = int64_t;
#define rep(i, n) for (int i = 0; i < ((int)(n)); i++) // 0-indexed昇順
// union by size + path having
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_) {
    par.resize(sz_);
    siz.assign(sz_, 1LL); // 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() {
  int N, K, L;
  cin >> N >> K >> L;

  auto t1 = UnionFind(N);
  rep(i, K) {
    int p, q;
    cin >> p >> q;
    p--, q--;
    t1.merge(p, q);
  }
  auto t2 = UnionFind(N);
  rep(i, L) {
    int r, s;
    cin >> r >> s;
    r--, s--;
    t2.merge(r, s);
  }

  vector<int> res(N, 0);
  rep(i, N) {
    for (int j = i; j < N; j++) {
      if (t1.issame(i, j) && t2.issame(i, j)) {
        res[i]++;
        if (i != j)
          res[j]++;
      }
    }
  }
  rep(i, N) { cout << res.at(i) << " "; }
  cout << endl;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;
using ll = int64_t;
#define rep(i, n) for (int i = 0; i < ((int)(n)); i++) // 0-indexed昇順
// union by size + path having
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_) {
    par.resize(sz_);
    siz.assign(sz_, 1LL); // 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() {
  int N, K, L;
  cin >> N >> K >> L;

  auto t1 = UnionFind(N);
  rep(i, K) {
    int p, q;
    cin >> p >> q;
    p--, q--;
    t1.merge(p, q);
  }
  auto t2 = UnionFind(N);
  rep(i, L) {
    int r, s;
    cin >> r >> s;
    r--, s--;
    t2.merge(r, s);
  }

  map<pair<int, int>, int> M;
  rep(i, N) { M[{t1.root(i), t2.root(i)}]++; }
  rep(i, N) { cout << M[{t1.root(i), t2.root(i)}] << " "; }
  cout << endl;
}