Language: C++

#include <bits/stdc++.h>

#define debug(var) std::cout << #var << " : " << var << " , ";

namespace Jin
{
template <class T, class Func>
class SegmentTree
{
private:
	std::vector<T> data;
	size_t height;
	size_t bottom_size;
	Func func;
	T invalid;

	T get(size_t l, size_t r, size_t k, size_t left, size_t right) const
	{
		if (right <= l || r <= left)
			return invalid;
		if (l <= left && right <= r)
			return data[k];
		T a = get(l, r, k * 2 + 1, left, (left + right) / 2);
		T b = get(l, r, k * 2 + 2, (left + right) / 2, right);
		return func(a, b);
	}

public:
	template <class Itr>
	SegmentTree(Itr first, Itr last, Func func, T invalid) : func(func), invalid(invalid)
	{
		size_t dif = std::distance(first, last);
		bottom_size = 1;
		height = 1;
		while (bottom_size < dif)
		{
			bottom_size <<= 1;
			++height;
		}
		data.resize(2 * bottom_size - 1, invalid);
		for (size_t i = 0; i < dif; ++i, ++first)
			update(i, *first);
	}

	void update(size_t i, int value)
	{
		i += bottom_size - 1;
		data[i] = value;
		while (i > 0)
		{
			i = (i - 1) / 2;
			data[i] = func(data[i * 2 + 1], data[i * 2 + 2]);
		}
	}

	T get(size_t l, size_t r) const
	{
		return get(l, r, 0, 0, bottom_size);
	}

	void show() const
	{
		for (size_t i = 0; i < 2 * bottom_size - 1; ++i)
		{
			std::cout << data[i] << ",";
			if (!((i + 2) & (i + 1)))
				std::cout << '\n';
		}
	}
};

template <class T, class Itr, class Func>
auto make_SegmentTree(Itr first, Itr last, Func func, T init)
{
	return SegmentTree<T, Func>(first, last, func, init);
}

template <class T>
class UnionFind
{

private:
	std::vector<T> par;//par[i] == iだったらi番目の要素が親
	
public:
	UnionFind(int N):par(N){
		for(auto &v : par)v = i;
	}
	
	T get_root(T arg){
		if(par[arg] == arg)return arg;
		return par[arg] = root(par[arg]);
	}

	void unite_tree(int x , int y){
		int root_x = get_root(x);
		int root_y = get_root(y);
		if(root_x == root_y)return;
		par[root_x] = root_y;
	}

	bool is_same(int x , int y){
		int root_x = get_root(x);
		int root_y = get_root(y);
		return (root_x == root_y);
	}

};

} // namespace Jin

int main(){


    int N , M; std::cin >> N >> M;
    std::vector<int> P(N); for(auto &v : P)std::cin >> v;
    Jin::UnionFind<int> tree(N);

    for(int i = 0; i < M; i++){
        int x , y;
        std::cin >> x >> y;
        tree.unite_tree(x - 1 , y - 1);
    }

    int ans = 0;
    for(int i = 0; i < N; i++){
        if(tree.is_same(i , P[i] - 1))ans++;
    }

    std::cout << ans;

    getchar();
    return 0;
}

Compiler output:
a.cc: In constructor 'Jin::UnionFind<T>::UnionFind(int)':
a.cc:87:39: error: 'i' was not declared in this scope
   87 |                 for(auto &v : par)v = i;
      |                                       ^
a.cc: In instantiation of 'T Jin::UnionFind<T>::get_root(T) [with T = int]':
a.cc:96:16:   required from 'void Jin::UnionFind<T>::unite_tree(int, int) [with T = int]'
   96 |                 int root_x = get_root(x);
      |                              ^~~~~~~~
a.cc:122:24:   required from here
  122 |         tree.unite_tree(x - 1 , y - 1);
      |         ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
a.cc:92:39: error: 'root' was not declared in this scope
   92 |                 return par[arg] = root(par[arg]);
      |                                   ~~~~^~~~~~~~~~