Problem p02762 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; ++i)
#define ll long long
#define P pair<int, int>
#define fast_io                                                                \
  ios_base::sync_with_stdio(false);                                            \
  cin.tie(0);                                                                  \
  cout.tie(0);
const int MOD = 1000000007;
const int INF = 2002002002;
const ll LLINF = 9009009009009009009;
using namespace std;

class UnionFind {
  // 各ノードが根である時の高さ
  // ノードが根でないときは意味をなさない
  vector<int> rank;
  // 各ノードが属する木の根
  // findSetするときのみ更新される
  vector<int> p;
  // 二つの根を結合
  void link(int rx, int ry) {
    if (rx == ry)
      return;
    if (rank[rx] > rank[ry])
      p[ry] = rx;
    else
      p[rx] = ry;
    if (rank[rx] == rank[ry])
      rank[ry]++;
  }

public:
  // 　根を作成
  //  その木の高さは0
  void makeSet(int x) {
    p[x] = x;
    rank[x] = 0;
  }
  // 初期化
  // 入力サイズ分のノードを確保
  // それらのノードをそれぞれ根とする木を作成
  // ノードの値は 0 ~ size-1
  UnionFind(int size) {
    rank.resize(size, 0);
    p.resize(size, 0);
    rep(i, size) makeSet(i);
  }
  // あるノードの属する木の根を返す
  // 根を探す過程で途中のノードの親も更新
  int findSet(int x) {
    if (x != p[x])
      p[x] = findSet(p[x]);
    return p[x];
  }
  // 二つのノードが同じ木にあるか判定
  bool same(int x, int y) { return findSet(x) == findSet(y); }
  // 二つのノードの属する木を結合
  void unite(int x, int y) { link(findSet(x), findSet(y)); }
};

int main() {
  fast_io int n, m, k;
  cin >> n >> m >> k;
  vector<vector<int>> fr(n), bl(n);
  int a, b;
  UnionFind tree(n);
  rep(i, m) {
    cin >> a >> b;
    a--;
    b--;
    fr[a].push_back(b);
    fr[b].push_back(a);
    tree.unite(a, b);
  }
  rep(i, k) {
    cin >> a >> b;
    a--;
    b--;
    bl[a].push_back(b);
    bl[b].push_back(a);
  }
  map<int, int> mp;
  rep(i, n) mp[tree.findSet(i + 1)]++;
  int ans;
  rep(i, n) {
    ans = mp[tree.findSet(i)] - 1 - fr[i].size();
    for (int block : bl[i])
      if (tree.same(i, block))
        ans--;
    cout << ans << endl;
  }
  return 0;
}

Fixed submission:
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; ++i)
#define ll long long
#define P pair<int, int>
#define fast_io                                                                \
  ios_base::sync_with_stdio(false);                                            \
  cin.tie(0);                                                                  \
  cout.tie(0);
const int MOD = 1000000007;
const int INF = 2002002002;
const ll LLINF = 9009009009009009009;
using namespace std;

class UnionFind {
  // 各ノードが根である時の高さ
  // ノードが根でないときは意味をなさない
  vector<int> rank;
  // 各ノードが属する木の根
  // findSetするときのみ更新される
  vector<int> p;
  // 二つの根を結合
  void link(int rx, int ry) {
    if (rx == ry)
      return;
    if (rank[rx] > rank[ry])
      p[ry] = rx;
    else
      p[rx] = ry;
    if (rank[rx] == rank[ry])
      rank[ry]++;
  }

public:
  // 　根を作成
  //  その木の高さは0
  void makeSet(int x) {
    p[x] = x;
    rank[x] = 0;
  }
  // 初期化
  // 入力サイズ分のノードを確保
  // それらのノードをそれぞれ根とする木を作成
  // ノードの値は 0 ~ size-1
  UnionFind(int size) {
    rank.resize(size, 0);
    p.resize(size, 0);
    rep(i, size) makeSet(i);
  }
  // あるノードの属する木の根を返す
  // 根を探す過程で途中のノードの親も更新
  int findSet(int x) {
    if (x != p[x])
      p[x] = findSet(p[x]);
    return p[x];
  }
  // 二つのノードが同じ木にあるか判定
  bool same(int x, int y) { return findSet(x) == findSet(y); }
  // 二つのノードの属する木を結合
  void unite(int x, int y) { link(findSet(x), findSet(y)); }
};

int main() {
  fast_io int n, m, k;
  cin >> n >> m >> k;
  vector<vector<int>> fr(n), bl(n);
  int a, b;
  UnionFind tree(n);
  rep(i, m) {
    cin >> a >> b;
    a--;
    b--;
    fr[a].push_back(b);
    fr[b].push_back(a);
    tree.unite(a, b);
  }
  rep(i, k) {
    cin >> a >> b;
    a--;
    b--;
    bl[a].push_back(b);
    bl[b].push_back(a);
  }
  map<int, int> mp;
  rep(i, n) mp[tree.findSet(i)]++;
  int ans;
  rep(i, n) {
    ans = mp[tree.findSet(i)] - 1 - fr[i].size();
    for (int block : bl[i])
      if (tree.same(i, block))
        ans--;
    cout << ans << endl;
  }
  return 0;
}