stablegradients/pie-gem5-bysrc huggingface dataset:
// Original C++ solution (slower):
#include <iostream>

#include <algorithm>

#include <iomanip>

#include <string>

#include <vector>

#include <math.h>

#include <queue>

#include <deque>

#include <stack>

#include <map>

const int MOD = 1e9+7;

#define PI 3.14159265359

typedef long long ll;

using namespace std;



ll par[100001];

ll ran[100001];

ll siz[100001];

vector<int> id[100001];

vector<int> num[100001];

 

void init(int n){

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

		par[i] = i;

		ran[i] = 0;

		siz[i] = 1;

	}

}

int find(int x){

	if (par[x] == x){

		return x;

	}else{

		par[x] = find(par[x]);

		return par[x];

	}

}

void unite(int x, int y){

	x = find(x);

	y = find(y);

	if (x == y) return;

 

	if (ran[x] < ran[y]){

		par[x] = y;

		siz[y] += siz[x];

	}else{

		par[y] = x;

		siz[x] += siz[y];

		if (ran[x] == ran[y]) ran[x]++;

	}

}

bool same(int x, int y){

	return find(x) == find(y);

}

int size(int x){

	return siz[find(x)];

}



int main(){

	int n, m;

	cin >> n >> m;

	init(n);

	vector<int> p(n+1);

	vector<pair<int, int> > vec(m);

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

		cin >> p[i];

	}

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

		int x, y;

		cin >> x >> y;

		unite(x, y);

	}

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

		id[find(i)].push_back(i);

		num[find(i)].push_back(p[i]);

	}

	int ans = 0;

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

		if (id[i].size()){

			sort(num[i].begin(), num[i].end());

			int coun = 0;

			for (auto x : id[i]){

				coun += binary_search(num[i].begin(), num[i].end(), x);

			}

			ans += coun;

		}

	}

	cout << ans << endl;

	return 0;

}

// Optimized solution to the same problem (faster):
#include <iostream>

#include <algorithm>

#include <iomanip>

#include <string>

#include <vector>

#include <math.h>

#include <queue>

#include <deque>

#include <stack>

#include <map>

const int MOD = 1e9+7;

#define PI 3.14159265359

typedef long long ll;

using namespace std;



ll par[100001];

ll ran[100001];

ll siz[100001];

 

void init(int n){

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

		par[i] = i;

		ran[i] = 0;

		siz[i] = 1;

	}

}

int find(int x){

	if (par[x] == x){

		return x;

	}else{

		par[x] = find(par[x]);

		return par[x];

	}

}

void unite(int x, int y){

	x = find(x);

	y = find(y);

	if (x == y) return;

 

	if (ran[x] < ran[y]){

		par[x] = y;

		siz[y] += siz[x];

	}else{

		par[y] = x;

		siz[x] += siz[y];

		if (ran[x] == ran[y]) ran[x]++;

	}

}

bool same(int x, int y){

	return find(x) == find(y);

}

int size(int x){

	return siz[find(x)];

}



int main(){

	int n, m;

	cin >> n >> m;

	init(n);

	vector<int> p(n+1);

	vector<pair<int, int> > vec(m);

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

		cin >> p[i];

	}

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

		int x, y;

		cin >> x >> y;

		unite(x, y);

	}

	int ans = 0;

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

		if (same(i, p[i])) ans++;

	}

	cout << ans << endl;

	return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<int, int> pii;

typedef pair<double,int> pdi;

const int N = 100005;

int a[N];

int fa[N];

vector<int> rec[N];

set<int> big[N];

map<int, int> mp;

int fat(int x)

{

    if(fa[x] == x)

        return x;

    return fa[x] = fat(fa[x]);

}

int main()

{



    int n, m, x, y, fax, fay;

    scanf("%d%d", &n, &m);

    for(int i = 1; i <= n; i++)

        fa[i] = i;

    for(int i = 1; i <= n; i++)

        scanf("%d", &a[i]);

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

    {

        scanf("%d%d", &x, &y);

        fax = fat(x);

        fay = fat(y);

        if(fax != fay)

            fa[fax] = fay;

    }

    int cnt = 0;

    for(int i = 1; i <= n; i++)

    {

        int f = fat(i);

        if(!mp.count(f))

        {

            mp.insert(pii(f, ++cnt));

        }

        int id = mp[f];

        big[id].insert(a[i]);

    }

    int ans = 0;

    for(int i = 1; i <= n; i++)

    {

        int f = fat(i);

        int id = mp[f];

        if(big[id].count(i))

            ans++;

    }

    printf("%d\n", ans);

}
















// Optimized solution to the same problem (faster):
#include<cstdio>

#define MAX 100001

int Tree[MAX];



int findRoot(int x){

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

  else{

    int tmp = findRoot(Tree[x]);

    Tree[x] = tmp;

    return tmp;

  }

}



using namespace std;



int main()

{

    int list[MAX];

    int belong[MAX];

   int n,m;

   while(scanf("%d%d",&n,&m)!=EOF){

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

        scanf("%d", &list[i]);

        Tree[i] = i;

    }

    while(m--){

        int a, b;

        scanf("%d%d", &a, &b);

        int na = findRoot(a);

        int nb = findRoot(b);

        if(na != nb) Tree[na] = nb;

    }

    int ans = 0;

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

        int t = findRoot(i);

        belong[list[i]] = t;

    }

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

        if(belong[i] == Tree[i])

        ans++;

    }

    printf("%d\n",ans);

   }

    return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<iostream>

#include<cstdio>

#include<string.h>

#include<algorithm>

#include<vector>

using namespace std;



int n,m,block;

vector<int> vec[100005];

bool vis[100005];

int part[100005],p[100005];



void dfs(int u, int fa)

{

    vis[u]=true;

    part[u]=block;

    for (int i=0; i<vec[u].size(); i++)

    {

        int v=vec[u][i];

        if (vis[v]) continue;

        if (v==fa) continue;

        dfs(v,u);

    }

}



int main()

{

    scanf("%d%d",&n,&m);

    for (int i=1; i<=n; i++)

    {

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

    }

    for (int i=1; i<=m; i++)

    {

        int a,b; scanf("%d%d",&a,&b);

        vec[a].push_back(b);

        vec[b].push_back(a);

    }

    memset(vis,false,sizeof(vis));

    block=1;

    for (int i=1; i<=n; i++)

    {

        if (vis[i]) continue;

        dfs(i,-1);

        block++;

    }

    int ans=0;

    for (int i=1; i<=n; i++)

    {

        if (part[i]==part[p[i]] || i==p[i])

        {

            ans++;

        }

    }

    cout<<ans<<endl;

    return 0;

}


// Optimized solution to the same problem (faster):
#include<cstdio>

#define MAX 100001

int Tree[MAX];



int findRoot(int x){

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

  else{

    int tmp = findRoot(Tree[x]);

    Tree[x] = tmp;

    return tmp;

  }

}



using namespace std;



int main()

{

    int list[MAX];

    int belong[MAX];

   int n,m;

   while(scanf("%d%d",&n,&m)!=EOF){

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

        scanf("%d", &list[i]);

        Tree[i] = i;

    }

    while(m--){

        int a, b;

        scanf("%d%d", &a, &b);

        int na = findRoot(a);

        int nb = findRoot(b);

        if(na != nb) Tree[na] = nb;

    }

    int ans = 0;

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

        int t = findRoot(i);

        belong[list[i]] = t;

    }

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

        if(belong[i] == Tree[i])

        ans++;

    }

    printf("%d\n",ans);

   }

    return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<iostream>

#include <stdio.h>

#include<algorithm>

#include<string.h>

#include<cmath>

#include <vector>

#include<set>

using namespace std;

int p[100005];

struct node{

    int er;

    int index;

}f[100005];

int flag[1000005]={0};

int Find(int x){return f[x].er!=x?f[x].er=Find(f[x].er):f[x].er;}

void Union(int x,int y)

{

    int fx=Find(x),fy=Find(y);

    f[fx].er=fy;

}

bool cmp(node a,node b)

{

    return (a.er<b.er);

}

int main()

{

    int n,m;

    scanf("%d%d",&n,&m);

    int sum=0;

    for(int i=1;i<=n;i++)

    {

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

        f[i].er=i;

        f[i].index=i;

    }

    for(int i=1;i<=m;i++)

    {

        int x,y;scanf("%d%d",&x,&y);

        Union(x,y);

    }

    for(int i=1;i<=n;i++)

        f[i].er=Find(i);

    sort(f+1,f+n+1,cmp);

    int l=1,r=2;

    while(1)

    {

        int qw=f[l].er;

        while(qw==f[r].er){

            r++;

            if(r>n)break;

        }

        for(int i=l;i<r;i++)

        {

            flag[f[i].index]=qw;

        }

        for(int i=l;i<r;i++)

        {

            if(flag[p[f[i].index]]==qw)sum++;

        }

        if(r>n)break;

        else l=r;

    }

    printf("%d",sum);

}


// Optimized solution to the same problem (faster):
#include<cstdio>

#define MAX 100001

int Tree[MAX];



int findRoot(int x){

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

  else{

    int tmp = findRoot(Tree[x]);

    Tree[x] = tmp;

    return tmp;

  }

}



using namespace std;



int main()

{

    int list[MAX];

    int belong[MAX];

   int n,m;

   while(scanf("%d%d",&n,&m)!=EOF){

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

        scanf("%d", &list[i]);

        Tree[i] = i;

    }

    while(m--){

        int a, b;

        scanf("%d%d", &a, &b);

        int na = findRoot(a);

        int nb = findRoot(b);

        if(na != nb) Tree[na] = nb;

    }

    int ans = 0;

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

        int t = findRoot(i);

        belong[list[i]] = t;

    }

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

        if(belong[i] == Tree[i])

        ans++;

    }

    printf("%d\n",ans);

   }

    return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <cstdio>

#include <iostream>

using namespace std;

const int maxn = 100005;

int father[maxn],p[maxn];   //  储存i的father父节点

int n,m;

void makeSet() {

    for (int i = 0; i < maxn; i++)

        father[i] = i;

}



int findRoot(int x) {   //  迭代找根节点

    int root = x; // 根节点

    while (root != father[root]) { // 寻找根节点

        root = father[root];

    }

    while (x != root) {

        int tmp = father[x];

        father[x] = root; // 根节点赋值

        x = tmp;

    }

    return root;

}



void Union(int x, int y) {  //  将x所在的集合和y所在的集合整合起来形成一个集合。

    int a, b;

    a = findRoot(x);

    b = findRoot(y);

    father[a] = b;  // y连在x的根节点上   或father[b] = a为x连在y的根节点上；

}



int main(){

	makeSet();

	scanf("%d%d",&n,&m);

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

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

	}

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

		int x,y;

		scanf("%d%d",&x,&y);

		Union(x,y);

		//cout << father[x] << father[y] << endl;

	}

	int ans = 0;

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

		if (findRoot(i) == findRoot(p[i])) ans++;

	}

	printf("%d\n",ans);

	return 0;

}

// Optimized solution to the same problem (faster):
#include<cstdio>

#define MAX 100001

int Tree[MAX];



int findRoot(int x){

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

  else{

    int tmp = findRoot(Tree[x]);

    Tree[x] = tmp;

    return tmp;

  }

}



using namespace std;



int main()

{

    int list[MAX];

    int belong[MAX];

   int n,m;

   while(scanf("%d%d",&n,&m)!=EOF){

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

        scanf("%d", &list[i]);

        Tree[i] = i;

    }

    while(m--){

        int a, b;

        scanf("%d%d", &a, &b);

        int na = findRoot(a);

        int nb = findRoot(b);

        if(na != nb) Tree[na] = nb;

    }

    int ans = 0;

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

        int t = findRoot(i);

        belong[list[i]] = t;

    }

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

        if(belong[i] == Tree[i])

        ans++;

    }

    printf("%d\n",ans);

   }

    return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<bits/stdc++.h>

using namespace std;

#define INF 0x3f3f3f3f

const double PI=acos(-1.0);

const int maxn=1e5+5;

int f[maxn];

int Find(int x)

{

	return (f[x]==x)?x:(f[x]=Find(f[x]));

}

void Union(int x,int y)

{

	int fx=Find(x),fy=Find(y);

	f[fx]=fy;

	fx=Find(x);

}

int main()

{

	int m,n,ans,a[maxn],x,y;

	while( cin>>n>>m )

	{

		vector<int>zu[maxn];

		bool vis[maxn];

		ans=0;

		int temp=0;

		for(int i=1;i<=n;i++)

		{

			cin>>a[i];

			ans+=(a[i]==i);

			vis[i]=false;

		}

		for(int i=1;i<=n;i++)

			f[i]=i;

		for(int i=1;i<=m;i++)

		{

			cin>>x>>y;

			Union(x,y);

		}

		for(int i=1;i<=n;i++)

			int ll=Find(i);

		for(int i=1;i<=n;i++)

			if( f[a[i]]==f[i] )

				temp++;

		cout<<max(ans,temp)<<endl;

	}

}


// Optimized solution to the same problem (faster):
#include<cstdio>

#define MAX 100001

int Tree[MAX];



int findRoot(int x){

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

  else{

    int tmp = findRoot(Tree[x]);

    Tree[x] = tmp;

    return tmp;

  }

}



using namespace std;



int main()

{

    int list[MAX];

    int belong[MAX];

   int n,m;

   while(scanf("%d%d",&n,&m)!=EOF){

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

        scanf("%d", &list[i]);

        Tree[i] = i;

    }

    while(m--){

        int a, b;

        scanf("%d%d", &a, &b);

        int na = findRoot(a);

        int nb = findRoot(b);

        if(na != nb) Tree[na] = nb;

    }

    int ans = 0;

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

        int t = findRoot(i);

        belong[list[i]] = t;

    }

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

        if(belong[i] == Tree[i])

        ans++;

    }

    printf("%d\n",ans);

   }

    return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>



using namespace std;



int niz[300050];

vector<int> adj[300050];

int comp[300050];

int ind[100050];





void dfs(int x,int k)

{

    comp[x]=k;

    for(auto y:adj[x])

        if(!comp[y])

            dfs(y,k);

}



int main()

{

    int n,m;

    cin>>n>>m;

    for(int i=1;i<=n;i++)

       {

            cin>>niz[i];

            ind[niz[i]]=i;

       }

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

    {

        int x,y;

        cin>>x>>y;

        adj[x].push_back(y);

        adj[y].push_back(x);

    }





    int br_komp=0;

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

        if(comp[i]==0){

            br_komp++;

            dfs(i,br_komp);

        }

    }

    int res=0;

    for(int i=1;i<=n;i++)if(comp[i]==comp[ind[i]])res++;

    cout<<res;

    return 0;

}


// Optimized solution to the same problem (faster):
#include <iostream>

#include <fstream>

#include <cmath>

#include <algorithm>

#include <vector>

#include <set>

#include <map>

#include <stack>

#include <queue>

#include <cstdlib>

#include <cstdio>

#include <string>

#include <cstring>

#include <cassert>

#include <utility>

#include <iomanip>

#include <chrono>

#include <random>

#include <bitset>



using namespace std;



#define sz(x) (int) x.size()

#define unique(x) x.erase(unique(x.begin(), x.end()), x.end())

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

#define sqr(x) ((x) * (x)) 

#define y1 aksjdaskdjksjfksdjf

#define left kdnvldvoiwejifejg

#define right lkdsjflksdjfdjfk

#define prev asdasfsadjkjsdfjs

#define tm aklsjdasjdasjdkdjjf

#define lcm hddalkwjeidjjhasda

#define random_shuffle asdasdd



const int MAXN = 105000;



int st[MAXN];



int getSet(int x) {

  if (st[x] == x)

    return x;

  st[x] = getSet(st[x]);

  return st[x];

}



void unite(int a, int b) {

  a = getSet(a); b = getSet(b);

  if (rand() & 1)

    swap(a, b);

  st[a] = b;

}



int n, m;

int p[MAXN];

int ans;



int main() { 



  scanf("%d %d", &n, &m);

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

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

    st[i] = i;

  }



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

    int from, to;

    scanf("%d %d", &from, &to);

    from--; to--;

    unite(from, to);

  }



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

    if (getSet(i) == getSet(p[i] - 1)) {

      ans++;

    }

  }



  cout << ans << endl;



  return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5+7;



int n, m;

int x, y;

int p[maxn];

vector<int> e[maxn];

bool vis[maxn];

int ans;

set<int> pos;

void dfs(int u)

{

    vis[u] = true;

    pos.insert(u);

    for(int &x : e[u]) if(!vis[x]) dfs(x);

}

int main()

{

    scanf("%d%d", &n, &m);

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

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

    }

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

        scanf("%d%d", &x, &y);

        e[x].push_back(y);

        e[y].push_back(x);

    }

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

        if(!vis[i]) {

            dfs(i);

            for(int x : pos) if(pos.find(p[x]) != pos.end()) ans++;

            pos.clear();

        }

    }

    printf("%d\n", ans);

}


// Optimized solution to the same problem (faster):
#include <iostream>

#include <fstream>

#include <cmath>

#include <algorithm>

#include <vector>

#include <set>

#include <map>

#include <stack>

#include <queue>

#include <cstdlib>

#include <cstdio>

#include <string>

#include <cstring>

#include <cassert>

#include <utility>

#include <iomanip>

#include <chrono>

#include <random>

#include <bitset>



using namespace std;



#define sz(x) (int) x.size()

#define unique(x) x.erase(unique(x.begin(), x.end()), x.end())

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

#define sqr(x) ((x) * (x)) 

#define y1 aksjdaskdjksjfksdjf

#define left kdnvldvoiwejifejg

#define right lkdsjflksdjfdjfk

#define prev asdasfsadjkjsdfjs

#define tm aklsjdasjdasjdkdjjf

#define lcm hddalkwjeidjjhasda

#define random_shuffle asdasdd



const int MAXN = 105000;



int st[MAXN];



int getSet(int x) {

  if (st[x] == x)

    return x;

  st[x] = getSet(st[x]);

  return st[x];

}



void unite(int a, int b) {

  a = getSet(a); b = getSet(b);

  if (rand() & 1)

    swap(a, b);

  st[a] = b;

}



int n, m;

int p[MAXN];

int ans;



int main() { 



  scanf("%d %d", &n, &m);

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

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

    st[i] = i;

  }



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

    int from, to;

    scanf("%d %d", &from, &to);

    from--; to--;

    unite(from, to);

  }



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

    if (getSet(i) == getSet(p[i] - 1)) {

      ans++;

    }

  }



  cout << ans << endl;



  return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<bits/stdc++.h>

#include <ext/pb_ds/assoc_container.hpp>

#include <ext/pb_ds/tree_policy.hpp>

#include <ext/pb_ds/detail/standard_policies.hpp>

using namespace std;

using namespace __gnu_pbds;

typedef tree<int, null_type, less_equal<int>, rb_tree_tag,

		tree_order_statistics_node_update> ordered_set;

typedef tree<int, null_type, less_equal<int>, rb_tree_tag,

		tree_order_statistics_node_update> indexed_multiset;



/*

int n , m;

int par[200005];

bool ok[200005];

int getpar(int node){

	if(par[node] == node)

		return node;

	return getpar(par[node]);

}

bool uni(int fnode , int snode){

	int ff = getpar(fnode) ,  ss = getpar(snode);

	if(ff==ss)

		return false;

	par[ff] = ss;

	return true;

}

*/

int n ,m ;

vector<int>vi2;

vector<vector<int>>vi(200005);

bool vis[200005];

int last[200005];

int group ;

void dfs(int node){

	last[node] = group;

	vis[node] = true;

	for(auto it : vi[node]){

		if(!vis[it])dfs(it);

	}

	

}

int main(){

	cin>>n>>m;

	vi2.resize(n);

	for(auto &it : vi2)

		cin>>it;

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

		int  u , v;

		cin>>u>>v;

		vi[u].push_back(v);

		vi[v].push_back(u);

	}

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

		if(!vis[i]){

			++group;

			dfs(i);

		}

	}

	int ans = 0;

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

		if(vi2[i] == i + 1 ||(last[i+1] == last[vi2[i]])){

			ans++;

		}

	}

	cout<<ans;

	/*

	cin>>n>>m;

	for(int i = 1; i <=n ;i++)

		par[i] = i;

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

		int u , v;

		cin>>u>>v;

		if(uni(u,v))cout<<u<<" "<<v<<endl;

	}

	*/

   	return 0;	

}


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



using namespace std;



#define all(v)			((v).begin()), ((v).end())

#define SZ(v)			((int)((v).size()))

#define clr(v, d)		memset(v, d, sizeof(v))

#define pb			    push_back



typedef long long ll;



vector<ll> par;

vector<ll> hi;



void init(int n){

   hi.resize(n,0);

   par.resize(n);

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

	   par[i] = i;

}



int root (int x) {

	if (par[x] == x)

		return x;

	else

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

}



bool Same (int x, int y) {

	return (root(x) == root(y));

}



void merge (int x, int y) {

	if (Same(x, y))

		return;

	x = root(x);

	y = root(y);

	if (hi[x] < hi[y])

		swap(x, y);

	par[y] = x;

	if (hi[x] == hi[y])

		hi[y]++;

}



int main() {



	ios_base::sync_with_stdio(false);

	cin.tie(nullptr);

	cout.tie(nullptr);



	int n, k;

	cin >> n >> k;

	vector<int> P(n);

	init(n+1);

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

		cin >> P[i];

	}

	int x, y;

	while (k--) {

		cin >> x >> y;

		merge(x, y);

		merge(y, x);

	}

	ll ans = 0;

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

		if (Same(P[i], i+1))

			ans++;

	}

	cout << ans;

	cout << endl;





	return 0;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <bits/stdc++.h>



using namespace std;



using ll = long long;

const int MAX_N = 1e5 + 1;

int n, m;

int p[MAX_N], used[MAX_N];

bool visited1[MAX_N], visited2[MAX_N];

vector<int> g[MAX_N];



void Input() {

    scanf("%d %d", &n, &m);



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

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

        --p[i];

    }

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

        scanf("%d %d", &x, &y);

        g[x - 1].push_back(y - 1);

        g[y - 1].push_back(x - 1);

    }



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

        visited1[i] = visited2[i] = false;

}



void Dfs1(const int cur, const int gr) {

    visited1[cur] = true;

    used[p[cur]] = gr;



    for (auto dst : g[cur]) {

        if (visited1[dst]) continue;

        Dfs1(dst, gr);

    }

}



int Dfs2(const int cur, const int gr) {

    visited2[cur] = true;



    int res = (used[cur] == gr ? 1 : 0);

    for (auto dst : g[cur]) {

        if (visited2[dst]) continue;

        res += Dfs2(dst, gr);

    }



    return res;

}





int Solve() {

    int res = 0, gr = 1;



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

        if (visited1[v]) continue;

        Dfs1(v, gr);

        res += Dfs2(v, gr);

        ++gr;

    }



    return res;

}



int main() {

    Input();

    printf("%d\n", Solve());



    return 0;

}


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



using namespace std;



class UnionFind {

public:

    UnionFind(int size) : data(size, -1) {}



    bool UnionSet(int x, int y) {

        x = root(x); y = root(y);

        if (x != y) {

            if (data[y] < data[x]) swap(x, y);

            data[x] += data[y]; data[y] = x;

        }

        return x != y;

    }

    bool FindSet(int x, int y) { return root(x) == root(y); }

    int size(int x) { return -data[root(x)]; }



private:

    std::vector<int> data;

    int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }

};





int main() {

    cin.tie(0); ios::sync_with_stdio(false);



    int n, m;



    cin >> n >> m;

    vector<int> p(n);

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

        cin >> p[i];

        --p[i];

    }



    UnionFind uf(n);

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

        cin >> x >> y;

        uf.UnionSet(x - 1, y - 1);

    }



    int cnt = 0;

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

        if (uf.FindSet(i, p[i])) ++cnt;



    cout << cnt << endl;



    return 0;

}


// Fastest known solution for this problem: