Problem p03354 (C++)

Buggy submission (status: Runtime Error):
#include "algorithm"
#include "cstring"
#include "iostream"
#include "math.h"
#include "queue"
#include "stack"
#include "string"
#include "vector"

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<vector<int>> mat;

// UnionFind
const int MAX_N = 10100;
const int MAX_Q = 10100;
struct UnionFind {
  int par[MAX_N];    // 親
  int height[MAX_N]; // 木の深さ
  int size[MAX_N];   // 子の数

  // n要素で初期化
  void init(int n) {
    for (int i = 0; i < n; i++) {
      par[i] = i;
      height[i] = 0;
      size[i] = 1;
    }
  }

  // 木の根を求める
  int find(int x) {
    if (par[x] == x) {
      return x;
    } else {
      return par[x] = find(par[x]);
    }
  }

  // xとyの属する集合を併合
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return;
    }

    if (height[x] < height[y]) {
      par[x] = y;
      size[y] = size[x] + size[y];
    } else {
      par[y] = x;
      size[x] = size[x] + size[y];
      if (height[x] == height[y]) {
        height[x]++;
      }
    }
  }

  // xとyが同じ集合に属するか否か
  bool same(int x, int y) { return find(x) == find(y); }
};

int main() {
  int n, m;
  cin >> n >> m;
  int p[MAX_N];
  for (int i = 0; i < n; i++) {
    cin >> p[i];
    p[i]--;
  }
  UnionFind uf;
  uf.init(n);
  int x[MAX_Q], y[MAX_Q];
  for (int i = 0; i < m; i++) {
    cin >> x[i] >> y[i];
    x[i]--;
    y[i]--;
    uf.unite(x[i], y[i]);
  }
  int ans = 0;
  for (int i = 0; i < n; i++) {
    if (uf.same(i, p[i])) {
      ans++;
    }
  }
  cout << ans << "\n";
}


Fixed submission:
#include "algorithm"
#include "cstring"
#include "iostream"
#include "math.h"
#include "queue"
#include "stack"
#include "string"
#include "vector"

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<vector<int>> mat;

// UnionFind
const int MAX_N = 100100;
const int MAX_Q = 100100;
struct UnionFind {
  int par[MAX_N];    // 親
  int height[MAX_N]; // 木の深さ
  int size[MAX_N];   // 子の数

  // n要素で初期化
  void init(int n) {
    for (int i = 0; i < n; i++) {
      par[i] = i;
      height[i] = 0;
      size[i] = 1;
    }
  }

  // 木の根を求める
  int find(int x) {
    if (par[x] == x) {
      return x;
    } else {
      return par[x] = find(par[x]);
    }
  }

  // xとyの属する集合を併合
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return;
    }

    if (height[x] < height[y]) {
      par[x] = y;
      size[y] = size[x] + size[y];
    } else {
      par[y] = x;
      size[x] = size[x] + size[y];
      if (height[x] == height[y]) {
        height[x]++;
      }
    }
  }

  // xとyが同じ集合に属するか否か
  bool same(int x, int y) { return find(x) == find(y); }
};

int main() {
  int n, m;
  cin >> n >> m;
  int p[MAX_N];
  for (int i = 0; i < n; i++) {
    cin >> p[i];
    p[i]--;
  }
  UnionFind uf;
  uf.init(n);
  int x[MAX_Q], y[MAX_Q];
  for (int i = 0; i < m; i++) {
    cin >> x[i] >> y[i];
    x[i]--;
    y[i]--;
    uf.unite(x[i], y[i]);
  }
  int ans = 0;
  for (int i = 0; i < n; i++) {
    if (uf.same(i, p[i])) {
      ans++;
    }
  }
  cout << ans << "\n";
}