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

}


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

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: 1.3982629154436754x):
#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;	

}
// 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: 1.4349122299593426x):
#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;	

}
// 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: 8.949248739337387x):
#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;

}
// 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.545256534045706x):
#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;

}
// 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.3592064426334463x):
#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;

}
// 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.4970198998765354x):
#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;

}
// 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.183813947428344x):
#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;

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

}


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

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

}


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

}