stablegradients/pie-gem5-pairs huggingface dataset:
// Slower C++ solution:
#include<iostream>  

#include<algorithm>  

#include<cstring>  

#include<cstdio>  

  

using namespace std;



const int inf = 0x3f3f3f3f;



struct node

{

    int u,v;

};

node e[200050];

int head[100050],vis[100050],tr[100050],a[100050];

int cnt;

int n,m;



void addedge(int u,int v)

{

    e[cnt].v=v;

    e[cnt].u=head[u];

    head[u]=cnt++;

}



int findx(int x)

{

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

    return tr[x]=findx(tr[x]);

}

void merge(int u, int v)  

{

    int fx=findx(u);

    int fy=findx(v);

    if(tr[fy]!=fx)

        tr[fy]=fx;

}

void dfs(int u)

{  

    vis[u]=1;  

    for(int i=head[u];i!=-1;i=e[i].u)

    {  

        int v=e[i].v;

        if(!vis[v])

        {

            tr[v]=cnt;

            dfs(v);

        }

    }

}

void init()

{

    cnt=0;

    memset(head,-1,sizeof(head));

    memset(vis,0,sizeof(vis));

    for(int i=0;i<n;i++) tr[i]=i;

}

int main()  

{

    init();

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

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

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

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

    {

        int x,y;

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

        addedge(x,y);

        addedge(y,x);

    }

    int ans=0;

    cnt=1;

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

    {

        if(!vis[i])

        {

            tr[i]=cnt;

            dfs(i);

            cnt++;

        }

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

            ans++;

    }

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

    return 0;

}

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

using namespace std;

const int N = 1e5 + 25, M = 1e6 + 25, oo = 1e9+7, mxmsk = 1 << 16;

const long long OO = 1e18+25;

    

#define f first

#define s second

    

int n,m,a[N], x,y, dsu[N], cnt;

    

int findparent(int u)

{

    if(u == dsu[u]) return u;

    return dsu[u] = findparent(dsu[u]);

}



void merge(int u, int v)

{

    u = findparent(u);

    v = findparent(v);

    dsu[u] = v;

}

    

int main() {

    iota(dsu, dsu+N, 0);

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

    for(int i=1; i<=n ; i++) scanf("%d",a+i);

    while(m--)

    {

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

        merge(x,y);

    }

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

    {

        cnt += (findparent(i) == findparent(a[i]));

    }

    printf("%d",cnt);

    return 0;

}
// Slower C++ solution:
/// However long the night,

///     The dawn will break

/// ICPC next year



#include<bits/stdc++.h>

using namespace std ;

const int N = 1e5+5 ;



int n ,m ,arr[N] ,u ,v ;

vector<int> adj[N] ;

bool vis[N] ;

int vid ,cur[N] ;

vector<int> idx ;

void dfs(int p){

    vis[p] = 1 ;

    cur[arr[p]] = vid ;

    idx.push_back(p);

    for(int ch:adj[p]){

        if(vis[ch]) continue;

        dfs(ch) ;

    }

}

int main(){

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

    for(int i=1;i<=n;++i) scanf("%d",arr+i);

    while(m--){

        scanf("%d%d",&u,&v);

        adj[u].push_back(v);

        adj[v].push_back(u);

    }

    int ans = 0 ;

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

        if(vis[i]) continue ;

        idx.clear() ;

        ++vid ;

        dfs(i) ;

        for(int j:idx)

            if(cur[j]==vid) ++ans ;

    }

    cout << ans ;

    return 0;

}


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

using namespace std;

const int N = 1e5 + 25, M = 1e6 + 25, oo = 1e9+7, mxmsk = 1 << 16;

const long long OO = 1e18+25;

    

#define f first

#define s second

    

int n,m,a[N], x,y, dsu[N], cnt;

    

int findparent(int u)

{

    if(u == dsu[u]) return u;

    return dsu[u] = findparent(dsu[u]);

}



void merge(int u, int v)

{

    u = findparent(u);

    v = findparent(v);

    dsu[u] = v;

}

    

int main() {

    iota(dsu, dsu+N, 0);

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

    for(int i=1; i<=n ; i++) scanf("%d",a+i);

    while(m--)

    {

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

        merge(x,y);

    }

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

    {

        cnt += (findparent(i) == findparent(a[i]));

    }

    printf("%d",cnt);

    return 0;

}
// Slower C++ solution:
#include<bits/stdc++.h>

#define LL long long

#define inf 0x3fffffffffffffff

using namespace std;



int n,m,p[100010],v[100010];

vector<int> e[100010];

set<int> id,pe;



void dfs(int x)

{

    v[x]=1;

    id.insert(x);

    pe.insert(p[x]);

    for (auto y:e[x])

        if (!v[y]) dfs(y);

}



int main()

{

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

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

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

    int x,y;

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

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

        e[x].push_back(y),

        e[y].push_back(x);

    memset(v,0,sizeof(v));

    int ans=0;

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

        if (!v[i])

        {

            id.clear();pe.clear();

            dfs(i);

            for (auto x:id)

                if (pe.find(x)!=pe.end()) ans++;

        }

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

    return 0;

}

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

using namespace std;

const int N = 1e5 + 25, M = 1e6 + 25, oo = 1e9+7, mxmsk = 1 << 16;

const long long OO = 1e18+25;

    

#define f first

#define s second

    

int n,m,a[N], x,y, dsu[N], cnt;

    

int findparent(int u)

{

    if(u == dsu[u]) return u;

    return dsu[u] = findparent(dsu[u]);

}



void merge(int u, int v)

{

    u = findparent(u);

    v = findparent(v);

    dsu[u] = v;

}

    

int main() {

    iota(dsu, dsu+N, 0);

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

    for(int i=1; i<=n ; i++) scanf("%d",a+i);

    while(m--)

    {

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

        merge(x,y);

    }

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

    {

        cnt += (findparent(i) == findparent(a[i]));

    }

    printf("%d",cnt);

    return 0;

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

}

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

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

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

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

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

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

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

	}

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

}