// Original C++ solution (slower):
#include <iostream>

#include <vector>

#include <algorithm>

#include <map>

#include <set>

#include <queue>



using namespace std;



int main(){



	int n,m;

	vector<int> p;

	map<int,int> s;

	map<int,vector<int>> xy;

	map<int,set<int>> z;

	char flag[100010];

	char ansFlag[100010];



	for(int i=0;i<100010;i++){

		flag[i]=0;

		ansFlag[i]=0;

	}



	cin>>n>>m;

	for(int i=0;i<n;i++){

		int tmp;

		cin>>tmp;

		p.push_back(tmp-1);

		s[tmp-1] = i;

	}

	for(int i=0;i<m;i++){

		int tmpX,tmpY;

		cin>>tmpX>>tmpY;

		xy[tmpX-1].push_back(tmpY-1);

		xy[tmpY-1].push_back(tmpX-1);

	}



	/*学習実施、どことどこが繋がってるのか？*/

	

	int ans=0;

	for(int i=0;i<n;i++){

		if(flag[i]==1)continue;

		queue<int> q;

		q.push(i);

		set<int> touch;

		touch.insert(i);

		flag[i]=1;

		while(q.size()!=0){

			int now = q.front();

			q.pop();

			if(xy[now].size()==0)continue;

			int size = xy[now].size();

			for(int j=0;j<size;j++){

				int next = xy[now].at(j);

				if(flag[next]==0){

					touch.insert(next);

					flag[next]=1;

					q.push(next);

				}

			}

		}

		/*

		for(int j=0;j<n;j++){

			int targetPos = p[j];

			if(touch.count(targetPos)==1){

				ans++;

			}

		}

		*/

		for(auto itr = touch.begin(); itr != touch.end();itr++){

			int targetPos = p[*itr];

			if(touch.count(targetPos)==1){

				ans++;

			}

		}

		/*

		for(auto itr = touch.begin(); itr != touch.end(); itr++){

			for(auto itr2 = itr; itr2 != touch.end() ;itr2++){

				z[*itr].insert(*itr2);

				z[*itr2].insert(*itr);

			}

		}*/

	}





	/*学習結果について表示してみる。*/

	

	/*

	for(int i=0;i<n;i++){

		cout<<"i="<<i<<" next = ";

		for(auto itr = xy[i].begin(); itr != xy[i].end();itr++){

			cout<<*itr<<" ";

		}

		cout<<endl;

	}

	*/

	

	for(int i=0;i<n;i++){

		int targetPos = p[i];

		if(z[i].count(targetPos)==1){

			ans++;

		}

	}



	cout<<ans<<endl;

	return 0;



}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;



#define lli long long int

#define REP(i,s,n) for(int i=s;i<n;i++)

#define MOD 1000000007

#define NUM 2520

#define INF (1LL<<50)

#define DEBUG 0

#define mp(a,b) make_pair(a,b)

#define SORT(V) sort(V.begin(),V.end())

#define PI (3.141592653589794)



typedef struct UnionFind{

	vector<lli> par; //par[i]:iの親番号 par[3] = 2 : 3の親が2

	vector<lli> size;//size[i]:iの大きさ 自分のみのときは1,根っこにsizeを持たせる*/



	UnionFind(int N){/*最初はすべてが根であると初期化*/

		REP(i,0,N){

			par.push_back(i);

			size.push_back(1);

		}

	}



	lli root(lli x){/*データxが属する木の根を再起で得る root(x) = {xの木の根}}*/

		if(par[x] == x)return x;

		return par[x] = root(par[x]);

	}



	void unite(lli x,lli y){/*xとyの併合*/

		lli rx = root(x);

		lli ry = root(y);

		if(rx == ry)return;

		par[rx] = ry; /*xとyの根が同じじゃない: xの根をrxをyの根ryに変更する */

		lli resize = size[rx] + size[ry];

		size[rx] = resize;

		size[ry] = resize;

	}



	bool same(lli x,lli y){

		lli rx = root(x);

		lli ry = root(y);

		return rx == ry;

	}



	lli getSize(lli x){

		lli rx = root(x);

		return size[rx];

	}

};



void func(long long N, long long M, std::vector<long long> p, std::vector<long long> x, std::vector<long long> y){



    UnionFind uf(N);



    REP(i,0,M){

        uf.unite(x[i],y[i]);

    }



    lli ans = 0;

    REP(i,0,N){

        lli target = p[i];

        if(uf.same(target,i))ans++;

    }

    cout<<ans<<endl;



}



int main(){

    // cout << fixed << setprecision(5);



    long long N;

    scanf("%lld",&N);

    long long M;

    scanf("%lld",&M);

    std::vector<long long> p(N);

    for(int i = 0 ; i < N ; i++){

        scanf("%lld",&p[i]);

        p[i]--;

    }

    std::vector<long long> x(M);

    std::vector<long long> y(M);

    for(int i = 0 ; i < M ; i++){

        scanf("%lld",&x[i]);

        scanf("%lld",&y[i]);

        x[i]--,y[i]--;

    }

    func(N, M, std::move(p), std::move(x), std::move(y));

    return 0;

}


// Fastest known solution for this problem: