Problem p03354 (C++)

Buggy submission (status: Runtime Error):
// #pragma GCC optimize ("-O3","unroll-loops")
#include <algorithm>
#include <bitset>
#include <cassert>
#include <complex>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits.h>
#include <map>
#include <math.h>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>

#define REP(i, n) for (int i = 0; i < n; i++)
#define REPR(i, n) for (int i = n; i >= 0; i--)
#define FOR(i, m, n) for (int i = m; i < n; i++)
#define FORR(i, m, n) for (int i = m; i >= n; i--)
#define SORT(v, n) sort(v, v + n);
#define VSORT(v) sort(v.begin(), v.end());
#define REVERSE(v, n) reverse(v, v + n);
#define VREVERSE(v) reverse(v.begin(), v.end());
#define ll long long
#define pb(a) push_back(a)
#define m0(x) memset(x, 0, sizeof(x))
#define print(x) cout << x << '\n';
#define pe(x) cout << x << " ";
#define lb(v, n) lower_bound(v.begin(), v.end(), n);
#define ub(v, n) upper_bound(v.begin(), v.end(), n);
// #define int long long
#define all(x) (x).begin(), (x).end()
// #define double long double

using namespace std;

template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

// const int MOD = 1e9 + 7;
const ll INF = 1e17;
const int INT_INF = 1e9;
const double pi = acos(-1);
const double EPS = 1e-10;
typedef pair<int, int> P;
const int MAX = 200020;

int siz[MAX];  // 錬結成分のサイズ
int par[MAX];  // 親
int Rank[MAX]; // 木の深さ

// n要素で初期化
void init(int n) {
  REP(i, n) {
    par[i] = i;
    Rank[i] = 0;
    siz[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 (Rank[x] < Rank[y]) {
    par[x] = y;
    siz[x] += siz[y];
    siz[y] = siz[x];
  } else {
    siz[y] += siz[x];
    siz[x] = siz[y];
    par[y] = x;
    if (Rank[x] == Rank[y])
      Rank[x]++;
  }
}

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

int idx[100010];
signed main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N;
  cin >> N;
  int M;
  cin >> M;
  init(3 * N + 1);
  REP(i, N) {
    int p;
    cin >> p;
    idx[p] = i + 1;
    unite(p, i + 1 + N);
  }
  REP(i, M) {
    int x, y;
    cin >> x >> y;
    unite(idx[x] + N, idx[y] + N);
  }
  int ans = 0;
  FOR(i, 1, N + 1) {
    if (same(i, i + N))
      ans++;
  }
  print(ans);
}

Fixed submission:
// #pragma GCC optimize ("-O3","unroll-loops")
#include <algorithm>
#include <bitset>
#include <cassert>
#include <complex>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits.h>
#include <map>
#include <math.h>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>

#define REP(i, n) for (int i = 0; i < n; i++)
#define REPR(i, n) for (int i = n; i >= 0; i--)
#define FOR(i, m, n) for (int i = m; i < n; i++)
#define FORR(i, m, n) for (int i = m; i >= n; i--)
#define SORT(v, n) sort(v, v + n);
#define VSORT(v) sort(v.begin(), v.end());
#define REVERSE(v, n) reverse(v, v + n);
#define VREVERSE(v) reverse(v.begin(), v.end());
#define ll long long
#define pb(a) push_back(a)
#define m0(x) memset(x, 0, sizeof(x))
#define print(x) cout << x << '\n';
#define pe(x) cout << x << " ";
#define lb(v, n) lower_bound(v.begin(), v.end(), n);
#define ub(v, n) upper_bound(v.begin(), v.end(), n);
// #define int long long
#define all(x) (x).begin(), (x).end()
// #define double long double

using namespace std;

template <class T> inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

// const int MOD = 1e9 + 7;
const ll INF = 1e17;
const int INT_INF = 1e9;
const double pi = acos(-1);
const double EPS = 1e-10;
typedef pair<int, int> P;
const int MAX = 500020;

int siz[MAX];  // 錬結成分のサイズ
int par[MAX];  // 親
int Rank[MAX]; // 木の深さ

// n要素で初期化
void init(int n) {
  REP(i, n) {
    par[i] = i;
    Rank[i] = 0;
    siz[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 (Rank[x] < Rank[y]) {
    par[x] = y;
    siz[x] += siz[y];
    siz[y] = siz[x];
  } else {
    siz[y] += siz[x];
    siz[x] = siz[y];
    par[y] = x;
    if (Rank[x] == Rank[y])
      Rank[x]++;
  }
}

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

int idx[100010];
signed main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N;
  cin >> N;
  int M;
  cin >> M;
  init(3 * N + 1);
  REP(i, N) {
    int p;
    cin >> p;
    idx[p] = i + 1;
    unite(p, i + 1 + N);
  }
  REP(i, M) {
    int x, y;
    cin >> x >> y;
    unite(idx[x] + N, idx[y] + N);
  }
  int ans = 0;
  FOR(i, 1, N + 1) {
    if (same(i, i + N))
      ans++;
  }
  print(ans);
}