#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<numeric>
#include<limits>
#include<bitset>
#include<functional>
#include<type_traits>
#include<queue>
#include<stack>
#include<array>
#include<random>
#include<utility>

#include<boost/multi_array.hpp>
#include<boost/variant.hpp>
#include<boost/optional.hpp>
#include<boost/optional/optional_io.hpp>
#include<boost/range/irange.hpp>
#include<boost/range/algorithm.hpp>
#include<boost/range/adaptors.hpp>
#include<boost/range/size.hpp>
#include<boost/multiprecision/cpp_int.hpp>

#include<cstdlib>
#include<ctime>

#define FOREACH_STRUCT2(arg0, arg1, rng)\
for(auto const& p: rng)\
for(bool f = true; f;)\
for(auto const& arg0 = std::get<0>(p); f;)\
for(auto const& arg1 = std::get<1>(p); f; f=false)

#define FOREACH_STRUCT3(arg0, arg1, arg2, rng)\
for(auto const& p: rng)\
for(bool f = true; f;)\
for(auto const& arg0 = std::get<0>(p); f;)\
for(auto const& arg1 = std::get<1>(p); f;)\
for(auto const& arg2 = std::get<2>(p); f; f=false)

#define DEFINE_STRUCT2(arg0, arg1, stc)\
auto const& arg0 = std::get<0>(stc);\
auto const& arg1 = std::get<1>(stc)

#define DEFINE_STRUCT3(arg0, arg1, arg2, stc)\
DEFINE_STRUCT2(arg0, arg1, stc);\
auto const& arg2 = std::get<2>(stc)

namespace lib
{
	using namespace boost::range;
	template<std::uint64_t Mod>struct modnum;
	template<class T>constexpr T pow(T base, std::size_t p)
	{
		if (p == 0)
		{
			return T(1);
		}
		else if (p == 1)
		{
			return base;
		}
		else if (p == 2)
		{
			return base * base;
		}
		else if (p % 2 == 0)
		{
			return pow(pow(base, p / 2), 2);
		}
		else
		{
			return pow(pow(base, p / 2), 2)*base;
		}
	}
	template<std::uint64_t Mod>constexpr auto inverse(modnum<Mod> const&);

	template<std::uint64_t Mod>struct modnum
	{
		static constexpr auto mod = Mod;
		std::uint64_t val;
		modnum() = default;
		constexpr modnum(std::uint64_t v):val(v%Mod)
		{

		}

		constexpr auto& clamp()
		{
			val %= mod;
			return *this;
		}

		constexpr auto& operator+=(modnum const& v)
		{
			val += v.val;
			return clamp();
		}
		constexpr auto& operator-=(modnum const& v)
		{
			val += mod - v.val;
			return clamp();
		}
		constexpr auto& operator*=(modnum const& v)
		{
			val *= v.val;
			return clamp();
		}
		constexpr auto& operator/=(modnum const& v)
		{
			return operator*=(inverse(v));
		}
	};
#define MAKE_MODNUM_OPERATOR(op)\
	template<std::uint64_t Mod>constexpr auto operator op(modnum<Mod> lhs, modnum<Mod>const& rhs)\
	{\
		return lhs BOOST_PP_CAT(op,=) rhs;\
	}
	MAKE_MODNUM_OPERATOR(+);
	MAKE_MODNUM_OPERATOR(-);
	MAKE_MODNUM_OPERATOR(*);
	MAKE_MODNUM_OPERATOR(/);

	template<std::uint64_t Mod>constexpr auto inverse(modnum<Mod>const& base)
	{
		return pow(base, Mod - 2);
	}

	template<class T>constexpr T gcd(T a, T b)
	{
		return a > b ? gcd(b, a) : a == T() ? b : gcd(b%a, a);
	}

	constexpr int intlog2(std::int64_t x)
	{
		std::int64_t j = 2;
		for (auto i = 0; i < 63; ++i)
		{
			if (j > x)
			{
				return int(i);
			}
			j <<= 1;
		}
		return 63;
	}

	template<class T>class binary_indexed_tree
	{
		std::vector<T> ar;
		std::size_t size;
	public:
		binary_indexed_tree(std::size_t size_):ar(size_), size(size_)
		{

		}
		void add(T val, int index)
		{
			++index;
			while (index <= size)
			{
				ar[index - 1] += val;
				index += index & -index;
			}
		}
		auto get(int index)
		{
			++index;
			T ret{};
			while (index != 0)
			{
				ret += ar[index - 1];
				index -= index&-index;
			}
			return ret;
		}
	};

	template<class T>using p_queue = std::priority_queue<T, std::vector<T>, std::greater<>>;

	struct union_find_light
	{
		std::vector<int> upper;
		union_find_light(std::size_t size):upper(size, -1){}

		int group(int index)
		{
			if (upper[index] == -1)
			{
				return index;
			}
			else
			{
				auto ret = group(upper[index]);
				upper[index] = ret;
				return ret;
			}
		}

		bool merge(int x, int y)
		{
			auto gx = group(x);
			auto gy = group(y);
			if (gx != gy)
			{
				upper[gx] = gy;
				return true;
			}
			return false;
		}

		std::map<int, std::set<int>> get()
		{
			std::map<int, std::set<int>> ret;
			for (int i = 0; i < upper.size(); ++i)
			{
				ret[group(i)].emplace(i);
			}
			return ret;
		}

		std::set<int> tops()
		{
			std::set<int> ret;
			for (int i = 0; i < upper.size(); ++i)
			{
				ret.emplace(group(i));
			}
			return ret;
		}

		bool is_same_group(int x, int y)
		{
			return group(x) == group(y);
		}
	};

	template<class Selector>auto make_compare(Selector selector)
	{
		return [=](auto const& lhs, auto const& rhs) {return selector(lhs) < selector(rhs); };
	}

	template<class Iterator>auto make_range(Iterator first, Iterator last)
	{
		struct return_type
		{
			Iterator first;
			Iterator last;
			auto begin()const
			{
				return first;
			}
			auto end()const
			{
				return last;
			}
		};
		return return_type{ first, last };
	}

	template<class T>auto factorial_array(std::size_t max)
	{
		std::vector<T> ret(max + 1);
		ret[0] = 1;
		for (auto i : boost::irange<std::size_t>(1, max + 1))
		{
			ret[i] = ret[i - 1] * T(i);
		}
		return ret;
	}
	
	struct randomizer
	{
		std::mt19937_64 random;
		randomizer():random()
		{
			std::random_device device{};
			std::array<unsigned, 623> init;
			for (auto& v : init)
			{
				v = device();
			}
			std::seed_seq seq(init.begin(), init.end());
			random = std::mt19937_64(seq);
		}

		std::int64_t operator()()
		{
			return random();
		}

		std::int64_t operator()(std::int64_t max)//[0, max]の範囲
		{
			std::uniform_int_distribution<std::int64_t> dist(0, max);
			return dist(random);
		}

		std::int64_t operator()(std::int64_t min, std::int64_t max)//[min, max]の範囲
		{
			std::uniform_int_distribution<std::int64_t> dist(min, max);
			return dist(random);
		}

		template<class RandomAccessRange>void shuffle(RandomAccessRange& rng)
		{
			lib::random_shuffle(rng, random);
		}
	};

	auto const first = [](auto p) {return p.first; };
	auto const second = [](auto p) {return p.second; };

	template<class T, class F>struct seg_tree_base
	{
	private:
		std::vector<T> vec;
		std::size_t depth;
		F func;
	public:
		seg_tree_base(std::size_t depth_, F func_ = F()):vec((1 << (depth_ + 1)) - 1), depth(depth_), func(func_) {}

		T get(std::size_t first, std::size_t last)const//[first, last)の範囲
		{
			if (last <= first)
			{
				return T();
			}
			return get(first, last - first, 0);
		}

		void change(T const& val, std::size_t index)
		{
			change(val, index, 0);
		}
	private:
		T get(std::size_t first, std::size_t length, std::size_t dep)const
		{
			if (length == 1)
			{
				return vec[(std::size_t(1) << depth) + first - 1];
			}
			auto x = std::size_t(1) << dep;
			auto y = std::size_t(1) << (depth - dep);
			if (first % y == 0)
			{
				if (length == y)
				{
					return vec[x + first / y - 1];
				}
				else if (length > y)
				{
					return func(vec[x + first / y - 1], get(first + y, length - y, dep + 1));
				}
				else
				{
					return get(first, length, dep + 1);
				}
			}
			else
			{
				auto next = first / y + 1;
				if (next*y < first + length)
				{
					return func(
						get(first, next*y - first, dep + 1),
						get(next*y, length - (next*y - first), dep + 1));
				}
				else
				{
					get(first, length, dep + 1);
				}
			}
		}

		void change(T const& val, std::size_t index, std::size_t dep)
		{
			auto x = 1 << dep;
			auto y = 1 << (depth - dep);
			if (dep == depth)
			{
				vec[x + index - 1] = val;
			}
			else
			{
				change(val, index, dep + 1);
				auto ind = index / y;
				vec[x + ind - 1] = func(vec[(x << 1) + 2 * ind - 1], vec[(x << 1) + 2 * ind]);
			}
		}
	};
	template<class T>using basic_seg_tree = seg_tree_base<T, std::plus<>>;

	template<class T, class F>class calc_tree
	{
		int size;
		const int count = 32;
		boost::multi_array<boost::optional<std::pair<int, T>>, 2> inside;
		std::vector<int> depth;
		F func;
		union_find_light uf;

		void init(int now, int prev, int dep, std::vector<std::map<int, T>>const& edge)
		{
			depth[now] = dep;
			FOREACH_STRUCT2(index, value, edge[now])
			{
				if (index == prev)
				{
					continue;
				}
				inside[index][0] = std::make_pair(now, value);
				init(index, now, dep + 1, edge);
			}
		}

		std::tuple<T, int> get(int now, int dep)
		{
			T ret{};
			for (auto sft : boost::irange(0, count))
			{
				if (dep&(1 << sft))
				{
					DEFINE_STRUCT2(next, val, *inside[now][sft]);
					now = next;
					ret = func(ret, val);
				}
			}
			return std::make_tuple(ret, now);
		}
	public:
		template<class Range>calc_tree(int size_, F func_, Range const& rng):
			size(size_),
			inside(boost::extents[size][count]),
			depth(size),
			func(func_),
			uf(size)
		{
			std::vector<std::map<int, T>> edge(size);
			FOREACH_STRUCT3(a, b, val, rng)
			{
				if (uf.is_same_group(a, b))
				{
					throw std::invalid_argument("this is not tree");
				}
				uf.merge(a, b);
				edge[a].emplace(b, val);
				edge[b].emplace(a, val);
			}
			for (auto i : uf.tops())
			{
				init(i, -1, 0, edge);
			}
			for (auto k : boost::irange(1, count))
			{
				for (auto j : boost::irange(0, size))
				{
					if (inside[j][k - 1])
					{
						DEFINE_STRUCT2(next1, val1, *inside[j][k - 1]);
						if (inside[next1][k - 1])
						{
							DEFINE_STRUCT2(next2, val2, *inside[next1][k - 1]);
							inside[j][k] = std::make_pair(next2, func(val1, val2));
						}
					}
				}
			}
		}

		boost::optional<T> get_value(int x, int y)
		{
			if (!uf.is_same_group(x, y))
			{
				return boost::none;
			}
			if (depth[y] < depth[x])
			{
				std::swap(x, y);
			}
			T ret{};
			std::tie(ret, y) = get(y, depth[y] - depth[x]);
			if (x == y)
			{
				return ret;
			}
			for (auto sft = count - 1; sft >= 0; --sft)
			{
				if (inside[x][sft])
				{
					DEFINE_STRUCT2(next1, val1, *inside[x][sft]);
					DEFINE_STRUCT2(next2, val2, *inside[y][sft]);
					if (next1 != next2)
					{
						x = next1;
						y = next2;
						ret = func(func(val1, val2), ret);
					}
				}
			}
			return func(func(inside[x][0]->second, inside[y][0]->second), ret);
		}
	};
	template<class T, class Func, class Range>auto make_calc_tree(std::size_t size, Func func, Range const& rng)
	{
		return calc_tree<T, Func>(size, func, rng);
	}

	auto maxf = [](auto a, auto b) {return std::max(a, b); };
	auto minf = [](auto a, auto b) {return std::min(a, b); };
}

namespace out
{
	namespace detail
	{
		template<class>struct void_out
		{
			typedef void type;
		};
		template<class T>auto write(std::ostream& ost, T const& val)
			->typename void_out<decltype(ost << val)>::type
		{
			ost << val;
		}
		template<class T, class... Ts>void write(std::ostream& ost, T const& val, Ts const&... nexts)
		{
			write(ost, val);
			ost << " ";
			write(ost, nexts...);
		}
		template<class T, std::size_t... Is>void write_tuple(std::ostream& ost, T const& tuple, std::index_sequence<Is...>)
		{
			write(ost, std::get<Is>(tuple)...);
		}
		template<class... Ts>void write(std::ostream& ost, std::tuple<Ts...>const& tuple)
		{
			write_tuple(ost, tuple, std::make_index_sequence<sizeof...(Ts)>());
		}
		template<class T0, class T1>void write(std::ostream& ost, std::pair<T0, T1>const& pair)
		{
			write(ost, pair.first);
			ost << " ";
			write(ost, pair.second);
		}
		template<class T>void write(std::ostream& ost, std::vector<T>const& vec)
		{
			auto size = vec.size();
			if (size == 0)
			{
				return;
			}
			write(ost, vec[0]);
			for (auto i : boost::irange<std::size_t>(1, size))
			{
				ost << " ";
				write(ost, vec[i]);
			}
		}
		template<class T>void write(std::ostream& ost, boost::multi_array<T, 2>const& ar)
		{
			write(ost, ar[0][0]);
			for (auto const& v : lib::make_range(std::next(ar[0].begin()), ar[0].end()))
			{
				ost << " ";
				write(ost, v);
			}
			for (auto ite = std::next(ar.begin()); ite != ar.end(); ++ite)
			{
				ost << std::endl;
				write(ost, *ite->begin());
				for (auto const& v : lib::make_range(std::next(ite->begin()), ite->end()))
				{
					ost << " ";
					write(ost, v);
				}
			}
		}
		template<std::uint64_t Mod>void write(std::ostream& ost, lib::modnum<Mod>const& val)
		{
			ost << val.val;
		}
	}
	void write_line()
	{
		std::cout << std::endl;
	}
	template<class...Ts>void write_line(Ts const&... args)
	{
		detail::write(std::cout, args...);
		std::cout << std::endl;
	}
	void debug()
	{
		std::cerr << std::endl;
	}
	template<class...Ts>void debug(Ts const&... args)
	{
		detail::write(std::cerr, args...);
		std::cerr << std::endl;
	}
	template<class Range>void write_range(Range const& rng)
	{
		for (auto const& v : rng)
		{
			write_line(v);
		}
	}
	template<class Range>void debug_range(Range const& rng)
	{
		for (auto const& v : rng)
		{
			debug(v);
		}
	}
}

namespace adaptor = boost::adaptors;

void Main();
int main()
{
	std::cin.tie(nullptr);
	std::cin.sync_with_stdio(false);
	std::cout << std::fixed;
	Main();
}

typedef lib::modnum<1000000007> mod_t;
typedef std::pair<std::int64_t, std::int64_t> int64pair;

void Main()
{
	int N, M;
	std::cin >> N >> M;
	std::vector<int> p(N);
	for (auto& v : p)
	{
		std::cin >> v;
		--v;
	}
	lib::union_find_light uf(N);
	for (int i : boost::irange(0, M))
	{
		int x, y;
		std::cin >> x >> y;
		--x; --y;
		uf.merge(x, y);
	}
	int count = 0;
	for (int i : boost::irange(0, N))
	{
		if (uf.is_same_group(i, p[i]))
		{
			++count;
		}
	}
	out::write_line(count);
}

Measured memory_bytes: 1024