Problem p03356 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <bits/stdc++.h>
#include <bitset>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <string>
#include <utility>
#include <vector>
using namespace std;
using ll = long long;

#define FOR(i, a, b) for (int i = (a); i <= (b); i++)
#define RFOR(i, a, b) for (int i = (a); i >= (b); i--)
#define LFOR(i, a, b) for (long long int i = (a); i <= (b); i++)
#define LRFOR(i, a, b) for (long long int i = (a); i >= (b); i--)
#define MOD 1000000007
#define LLONG_MAXs 9223372036854775800

#define ALL(a) (a).begin(), (a).end()

#include <cmath>
#include <iostream>
using namespace std;

bool isPrimeNum(ll x) { // 素数である場合 true を返す
  if (x <= 1) { // 1以下である場合は素数でないことがすぐにわかる
    return false;
  }
  // sqrt( double型 ) は引数の平方根を double型で返すので、int型でキャスト
  int n = (int)sqrt((double)x);
  for (int i = 2; i <= n; i++) {
    if (x % i == 0) { // 割り切る整数がある場合、即判定終了
      return false;
    }
  }
  return true; // 割り切る整数がない場合、素数である
}

ll myPow(ll x, ll n, ll m) {
  if (n == 0)
    return 1;
  if (n % 2 == 0)
    return myPow(x * x % m, n / 2, m);
  else
    return x * myPow(x, n - 1, m) % m;
}

constexpr ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
constexpr ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
constexpr ll abs(ll a, ll b) {
  if (a >= b)
    return a - b;
  if (a < b)
    return b - a;
}
constexpr ll min(ll a, ll b) {
  if (a >= b)
    return b;
  if (a < b)
    return a;
}

constexpr ll max(ll a, ll b) {
  if (a >= b)
    return a;
  if (a < b)
    return b;
}

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

struct UnionFind {
  vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2

  UnionFind(int N) : par(N) { // 最初は全てが根であるとして初期化
    for (int i = 0; i < N; i++)
      par[i] = i;
  }

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

  void unite(int x, int y) { // xとyの木を併合
    int rx = root(x);        // xの根をrx
    int ry = root(y);        // yの根をry
    if (rx == ry)
      return; // xとyの根が同じ(=同じ木にある)時はそのまま
    par[rx] =
        ry; // xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
  }

  bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> que;

int main() {
  ll N, M;
  cin >> N >> M;
  ll x[N], y[N], A[N];
  UnionFind tree(N + 1);
  FOR(i, 0, N - 1) { cin >> A[i]; }
  // cout<<"1"<<endl;
  FOR(i, 0, M - 1) {
    cin >> x[i] >> y[i];
    tree.unite(x[i], y[i]);
  }
  // cout<<"2"<<endl;
  ll ans = 0;

  FOR(i, 0, N - 1) {
    // cout<<A[i]<<" "<<A[ A[i] -1]<<endl;
    if (tree.same(A[i], A[A[i] - 1]))
      ans++;
    // cout<<i<<endl;
  }
  cout << ans << endl;

  return 0;
}

Fixed submission:
#include <algorithm>
#include <bits/stdc++.h>
#include <bitset>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <string>
#include <utility>
#include <vector>
using namespace std;
using ll = long long;

#define FOR(i, a, b) for (int i = (a); i <= (b); i++)
#define RFOR(i, a, b) for (int i = (a); i >= (b); i--)
#define LFOR(i, a, b) for (long long int i = (a); i <= (b); i++)
#define LRFOR(i, a, b) for (long long int i = (a); i >= (b); i--)
#define MOD 1000000007
#define LLONG_MAXs 9223372036854775800

#define ALL(a) (a).begin(), (a).end()

#include <cmath>
#include <iostream>
using namespace std;

bool isPrimeNum(ll x) { // 素数である場合 true を返す
  if (x <= 1) { // 1以下である場合は素数でないことがすぐにわかる
    return false;
  }
  // sqrt( double型 ) は引数の平方根を double型で返すので、int型でキャスト
  int n = (int)sqrt((double)x);
  for (int i = 2; i <= n; i++) {
    if (x % i == 0) { // 割り切る整数がある場合、即判定終了
      return false;
    }
  }
  return true; // 割り切る整数がない場合、素数である
}

ll myPow(ll x, ll n, ll m) {
  if (n == 0)
    return 1;
  if (n % 2 == 0)
    return myPow(x * x % m, n / 2, m);
  else
    return x * myPow(x, n - 1, m) % m;
}

constexpr ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
constexpr ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
constexpr ll abs(ll a, ll b) {
  if (a >= b)
    return a - b;
  if (a < b)
    return b - a;
}
constexpr ll min(ll a, ll b) {
  if (a >= b)
    return b;
  if (a < b)
    return a;
}

constexpr ll max(ll a, ll b) {
  if (a >= b)
    return a;
  if (a < b)
    return b;
}

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

struct UnionFind {
  vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2

  UnionFind(int N) : par(N) { // 最初は全てが根であるとして初期化
    for (int i = 0; i < N; i++)
      par[i] = i;
  }

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

  void unite(int x, int y) { // xとyの木を併合
    int rx = root(x);        // xの根をrx
    int ry = root(y);        // yの根をry
    if (rx == ry)
      return; // xとyの根が同じ(=同じ木にある)時はそのまま
    par[rx] =
        ry; // xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
  }

  bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> que;

int main() {
  ll N, M;
  cin >> N >> M;
  ll x[M], y[M], A[N];
  UnionFind tree(N + 1);
  FOR(i, 0, N - 1) { cin >> A[i]; }
  // cout<<"1"<<endl;
  FOR(i, 0, M - 1) {
    cin >> x[i] >> y[i];
    tree.unite(x[i], y[i]);
  }
  // cout<<"2"<<endl;
  ll ans = 0;

  FOR(i, 0, N - 1) {
    // cout<<A[i]<<" "<<A[ A[i] -1]<<endl;
    if (tree.same(A[i], A[A[i] - 1]))
      ans++;
    // cout<<i<<endl;
  }
  cout << ans << endl;

  return 0;
}