stablegradients/pie-gem5-pairs huggingface dataset:
// Slower C++ solution:
#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;

}


// Faster C++ solution for the same problem (measured speedup: 17.358685985760673x):
#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;

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

}


// Faster C++ solution for the same problem (measured speedup: 4.767679469946433x):
#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;

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

}

// Faster C++ solution for the same problem (measured speedup: 6.655100301182505x):
#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;

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

	}

}


// Faster C++ solution for the same problem (measured speedup: 17.122504322314974x):
#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;

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

}
















// Faster C++ solution for the same problem (measured speedup: 2.6004309499228593x):
#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);

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

}


// Faster C++ solution for the same problem (measured speedup: 2.668589813829908x):
#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);

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

}
















// Faster C++ solution for the same problem (measured speedup: 9.15390390647993x):
#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;

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

}


// Faster C++ solution for the same problem (measured speedup: 3.62633094483385x):
#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;

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

}

// Faster C++ solution for the same problem (measured speedup: 1.390289344651316x):
#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;

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

	}

}


// Faster C++ solution for the same problem (measured speedup: 3.576991215118246x):
#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;

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

}


// Faster C++ solution for the same problem (measured speedup: 9.393833249959892x):
#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;

}