// Slower C++ solution:
#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;



}

// Faster C++ solution for the same problem (measured speedup: 1.1032015279569194x):
#include <bits/stdc++.h>

 

using namespace std;

 

#define lli long long int

#define lld long double

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

#define RREP(i,s,n) for(lli i=s;i>=n;i--)

#define MOD 1000000007

#define NUM 2520

#define DEBUG 0

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

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

#define PI (3.141592653589794)

#define INF (1LL<<50)



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];

	}

};



signed main(){



	lli n,m;

	cin>>n>>m;

	vector<lli> p(n);

	map<lli,lli> ind;

	UnionFind uf(n);

	REP(i,0,n){

		cin>>p[i];

		p[i]--;

		ind[p[i]] =i;

	}



	REP(i,0,m){

		lli x,y;

		cin>>x>>y;

		x--,y--;

		uf.unite(x,y);

	}



	lli cnt=0;

	REP(i,0,n){

		lli nowInd = p[i];

		if(uf.same(i,nowInd))cnt++;

	}



	cout<<cnt<<endl;



	return 0;

}