stablegradients/pie-gem5-pairs huggingface dataset:
// Slower C++ solution:
#include "bits/stdc++.h"

using namespace std;



//



#define RESIDUE(u,v) (capacity[u][v] - flow[u][v])

#define RCOST(u,v) (cost[u][v] + h[u] - h[v])

#define FOR(i,a,b) for(int i=(a);i<(b);++i)

#define REP(i,n)   FOR(i,0,n)

#define LL long long



int p[100001];

int ind[100001];



#define N 100001



int par[N];

int rnk[N];



void init_uf(){

  REP(i,N){

    par[i]=i;

    rnk[i]=0;

  }

}



int find(int x){

  if(par[x] == x)

    return x;

  else

    return find(par[x]);

}



void unite(int x,int y){

  x=find(x);

  y=find(y);

  if(x==y)

    return;

      

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

    par[x] = y;

  else{

    par[y] = x;

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

  }

}



bool same(int x,int y){

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

}



int main(){

  int n,m;

  cin>>n>>m;

  REP(i,n){

    cin>>p[i+1];

    ind[p[i+1]]=i+1;

  }



  init_uf();

  int dum1,dum2;

  REP(i,m){

    cin>>dum1>>dum2;

    unite(ind[dum1],ind[dum2]);

  }



  int ret = 0;

  REP(i,n){

    if(same(i+1,ind[i+1])) ret++;

  }

  cout<<ret<<endl;

  return 0;

}


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

using namespace std;



#define FOR(i,a,b) for(int i=(a);i<(b);++i)

#define REP(i,n)   FOR(i,0,n)

#define LL long long



class UnionFind{

private:

  std::vector<int> par;

  std::vector<int> rnk;

public:

  UnionFind(int n):par(n),rnk(n){

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

      par[i]=i;

      rnk[i]=0;

    }

  }

  

  int find(int x){

    if(par[x] == x)

      return x;

    else

      return find(par[x]);

  }



  void unite(int x,int y){

    x=find(x);

    y=find(y);

    if(x==y)

      return;

      

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

      par[x] = y;

    else{

      par[y] = x;

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

    }

  }



  bool same(int x,int y){

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

  }

};



int n,m;



int main(){

  cin>>n>>m;

  int tmp,tmp2;

  UnionFind un(2*n);

  REP(i,n){

    cin>>tmp;

    un.unite(i,n+tmp-1);

  }

  REP(i,m){

    cin>>tmp>>tmp2;

    un.unite(tmp-1,tmp2-1);

  }

  LL ret=0;

  REP(i,n)ret+=(un.same(i,n+i))?1:0;

  cout<<ret<<endl;

  return 0;

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



using namespace std;



#define inf 1<<30

#define pqueue priority_queue

#define mp make_pair

#define pb push_back

#define fn fill_n

typedef long long llong;

typedef unsigned long long ullong;

typedef pair<int, int> P;

struct UnionFind{

	int par[100001];



	UnionFind(){};

	UnionFind(int n){

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

			par[i] = i;

	};

	int find(int n){

		if(par[n] == n) return n;

		return par[n] = find(par[n]);

	};

	bool isSame(int a, int b){

		return find(a) == find(b);

	};

	void marge(int a, int b){

		a = find(a);

		b = find(b);

		if(a == b) return;

		else if(a < b)

			par[b] = a;

		else

			par[a] = b;

		return;

	};

};



int N, M;

int id[100001] = {};

UnionFind uf(100001);



int main(){

	cin >> N >> M;

	int in;

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

		cin >> in;

		id[in] = i;

	}

	int a, b;

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

		cin >> a >> b;

		uf.marge(a,b);

	}

	int cnt = 0;

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

		if(uf.isSame(i, id[i]))

			cnt++;



	cout << cnt << endl;



	return 0;

}

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



using namespace std;



#define inf 1<<30

#define pqueue priority_queue

#define mp make_pair

#define pb push_back

#define fn fill_n

typedef long long llong;

typedef unsigned long long ullong;

typedef pair<int, int> P;

struct UnionFind{

	vector<int> par, rank;



	UnionFind(){};

	UnionFind(int n){

		par.resize(n), rank.resize(n);

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

			par[i] = i, rank[i] = 0;

	};

	int find(int n){

		if(par[n] == n) return n;

		return par[n] = find(par[n]);

	};

	bool isSame(int a, int b){

		return find(a) == find(b);

	};

	void marge(int a, int b){

		a = find(a);

		b = find(b);

		if(a == b) return;

		if(rank[a] < rank[b]) swap(a,b);

		if(rank[a] == rank[b]) rank[a]++;

		par[b] = a;

		return;

	};

};



int N, M;

int id[100001] = {};

UnionFind uf;



int main(){

	cin >> N >> M;

	uf = UnionFind(N+1);

	int in;

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

		cin >> in;

		id[in] = i;

	}

	int a, b;

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

		cin >> a >> b;

		uf.marge(a,b);

	}

	int cnt = 0;

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

		if(uf.isSame(i, id[i]))

			cnt++;



	cout << cnt << endl;



	return 0;

}
// Slower C++ solution:
#include<iostream>

using namespace std;

typedef long long ll;

#define NODE_MAX 100001

int par[NODE_MAX],rk[NODE_MAX];

void init(){

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

    par[i]=i;

    rk[i]=0;

  }

}

int root(int x){

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

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

}

void unite(int x,int y){

  x = root(x);

  y = root(y);

  if(x==y) return;



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

    par[x] = y;

  }else{

    par[y] = x;

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

  }

}

bool same(int x,int y){

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

}

int main(){

  ll n,m,cnt=0;

  cin >> n >> m;

  init();

  ll p[n],x[m],y[m];

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

    cin >> p[i];

  }

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

    cin >> x[i]>>y[i];

    unite(x[i],y[i]);

  }

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

    if(same(i+1,p[i])){

      cnt++;

    }

  }

  cout << cnt << endl;

}


// Faster C++ solution for the same problem (measured speedup: 1.7598685618609642x):
// I SELL YOU...! 

#include<iostream>

#include<vector>

#include<algorithm>

#include<functional>

#include<queue>

#include<chrono>

#include<iomanip>

#include<map>

#include<set>

using namespace std;

using ll = long long;

using P = pair<ll,ll>;

using TP = tuple<ll,ll,ll>;

void init_io(){

  cin.tie(0);

  ios::sync_with_stdio(false);

  cout << setprecision(18);

}

class union_find{

  int n;

  vector<int> par,rk,size;

  public:

  union_find(int max_n){

    n = max_n+1;

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

      par.emplace_back(i);

      rk.emplace_back(0);

      size.emplace_back(1);

    }

  }

  int root(int x){

    vector<int> nodes;

    while(x!=par[x]){

      nodes.emplace_back(x);

      x = par[x];

    }

    for(auto v:nodes){

      par[v] = x;

    }

    return x;

  }

  void unite(int x,int y){

    x = root(x);

    y = root(y);

    if(x==y) return;

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

      par[x] = y;

      size[y] += size[x];

    }else{

      par[y] = x;

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

      size[x] += size[y];

    }

  }

  bool same(int x,int y){

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

  }

  int treesize(int x){

    return size[root(x)];

  }

};

signed main(){

  init_io();

  ll n,m,ans=0;

  cin >> n >> m;

  union_find uf(n);

  vector<ll> p(n),x(m),y(m);

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

    cin >> p[i];

    p[i]--;

  }

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

    cin >> x[i] >> y[i];

    x[i]--;

    y[i]--;

    uf.unite(x[i],y[i]);

  }

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

    if(uf.same(p[i],i)){

      ans++;

    }

  }

  cout << ans << endl;

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

//#pragma GCC optimize("O3")

//#pragma GCC target ("sse4")

using namespace std;

#define PB push_back

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

#define MEM(x,a) memset((x),a,sizeof((x)))

#define F first

#define S second

#define imx INT_MAX

#define inI(x) scanf("%d",&x)

#define inI2(x,y) scanf("%d %d",&x,&y)

#define inI3(x,y,z) scanf("%d %d %d",&x,&y,&z)

const long long MOD = (long long)(1e9+7);

const long long MMX = (long long)(1e18);

typedef long long LL;

vector<int>v[100005];

int n,m,num[100005],gr[100005],x,y,k,ans;

bitset<100005>go;

queue<int>q;

int main()

{

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

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

    {

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

    }

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

    {

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

        v[x].push_back(y);

        v[y].push_back(x);

    }

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

    {

        if(!go[i])

        {

            q.push(i);

            while(!q.empty())

            {

                k=q.front();

                go[k]=true;

                gr[k]=i;

                q.pop();

                for(int j=0;j<v[k].size();j++)

                {

                    if(!go[v[k][j]])

                    {

                        q.push(v[k][j]);

                    }

                }

            }

        }

    }

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

    {

        if(gr[i]==gr[num[i]])ans++;

    }

    printf("%d",ans);

}


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

using namespace std;



int p[100100];

int li[100100];

map<int,int> mp;



int fi(int nw)

{

	if(li[nw]==nw)return nw;

	return li[nw]=fi(li[nw]);

}



void uni(int l1,int l2)

{

	li[l1]=l2;

}



main()

{

	int n,m;

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

	for(int i=1;i<=n;i++)li[i]=i;

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

	{

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

		mp[p[i]]=i;

	}

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

	{

		int a,b;

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

		if(fi(a)!=fi(b))

		{

			uni(fi(a),fi(b));

		}

	}

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

	int ans=0;

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

	{

		if(li[mp[i]]==li[i])

		{

			ans++;

		}

	}

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

}
// Slower C++ solution:
/*

 * ARC097_D.cpp

 *

 *  Created on: May 12, 2018

 *      Author: 13743

 */



#include<iostream>

#include<vector>

#include<algorithm>

#include<queue>

#include<stack>

#include<unordered_set>



using namespace std;



vector<int> adj[100001];

int p[100001];

vector<vector<int>> comps;

int vis[100001];







void connected(int rt, int i) {

	if(vis[rt]) return;

	vis[rt] = i;

	comps[i].push_back(rt);

	for(int j=0; j<adj[rt].size(); j++) {

		connected(adj[rt][j], i);

	}

}



int main() {

	comps.resize(100000);

	int n, m;

	cin >> n >> m;

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

		cin >> p[i];

	}

	int x, y;

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

		cin >> x >> y;

		adj[x].push_back(y);

		adj[y].push_back(x);

	}



	int n2 = 1;

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

		if(vis[i] == 0) {

			connected(i, n2);

			n2++;

		}

	}

	int sumS = 0;

	for(int i=0; i<comps.size(); i++) {

		

		for(int j=0; j<comps[i].size(); j++) {

			if(vis[p[comps[i][j]]] == vis[comps[i][j]]) {sumS++;}

		}

	}



	cout << sumS << endl;

}






// Faster C++ solution for the same problem (measured speedup: 1.8719624732240696x):
/*

 * ARC097_D.cpp

 *

 *  Created on: May 14, 2018

 *      Author: 13743

 */



#include<iostream>

#include<algorithm>

#include<vector>

#include<stack>

#include<queue>

#include<string>

using namespace std;

typedef long long llong;



#define PB push_back

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

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

#define FOR(i,a,b) for(int i=(a); i<(b); ++i)

#define REP(i,n) FOR(i,0,n)

#define UNIQUE(a) a.erase(unique(ALL(a)), a.end())



int seqP[100001];

vector<int> adjL[100001];

int comps[100001];



void connected(int v, int num) {

	if(comps[v] > 0) return;

	comps[v] = num;

	REP(i, SZ(adjL[v])) {

		connected(adjL[v][i], num);

	}

}



int main() {

	cin.tie(0);

	ios::sync_with_stdio(false);



	int N, M;

	cin >> N >> M;

	REP(i, N) {

		cin >> seqP[i+1];

	}

	REP(i, M){

		int u, v;

		cin >> u >> v;

		adjL[u].PB(v);

		adjL[v].PB(u);

	}



	int numC = 1;

	FOR(i, 1, N+1) {

		if(comps[i] > 0) continue;

		connected(i, numC);

		++numC;;

	}



	int ans = 0;

	FOR(i, 1, N+1) {

		if(comps[seqP[i]] == comps[i]) {

			++ans;

		}

	}



	cout << ans << endl;

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

using namespace std;

#define rep(i,n) for (int (i)=(0);(i)<(int)(n);++(i))

using ll = long long;

using P = pair<int, int>;

using namespace std;



template<class T> void vin(vector<T>& v, int n) {

    v.resize(n);

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

        cin >> v[i];

    }

}



int p[101010];

vector<int> g[101010];

bitset<101010> flag;



void dfs(int v, vector<int>& num, vector<int>& pos) {

    flag[v] = 1;

    pos.push_back(v+1);

    num.push_back(p[v]);

    for (int& u : g[v]) {

        if (flag[u]) continue;

        dfs(u, num, pos);

    }

}



int main() {

    int N, M;

    cin >> N >> M;

    rep(i, N) cin >> p[i];

    rep(i, M) {

        int x, y;

        cin >> x >> y;

        x--; y--;

        g[x].push_back(y);

        g[y].push_back(x);

    }

    int ans = 0;

    rep(i, N) {

        vector<int> n, p;

        if (!flag[i]) dfs(i, n, p);

        sort(n.begin(), n.end());

        sort(p.begin(), p.end());

        int idx1=0, idx2=0;

        while (true) {

            if (idx1 >= n.size() or idx2 >= p.size()) break;

            if (n[idx1] == p[idx2]) {

                idx1++; idx2++;

                ans++;

            }

            else if (n[idx1] > p[idx2]) {

                idx2++;

            }

            else if (n[idx1] < p[idx2]) {

                idx1++;

            }

        }

    }

    cout << ans << endl;

    return 0;

}


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

using namespace std;

#define rep(i,n) for (int (i)=(0);(i)<(int)(n);++(i))

using ll = long long;

using P = pair<int, int>;

using namespace std;



template<class T> void vin(vector<T>& v, int n) {

    v.resize(n);

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

        cin >> v[i];

    }

}



struct UnionFind {

    static const int MAX = 1000000;

    int par[MAX];

    void init(int N) {

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

            par[i] = -1;

        }

    }

    void init() {

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

            par[i] = -1;

        }

    }

    int find(int x) {

        if (par[x] < 0) return x;

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

    }

    bool unite(int x, int y) {

        x = find(x);

        y = find(y);

        if (x == y) return false;

        if (par[x] > par[y]) {

            int tmp = x;

            x = y;

            y = tmp;

        }

        par[x] += par[y];

        par[y] = x;

        return true;

    }

    bool same(int x, int y) {

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

    }

    // そのグループの木の大きさを返す

    int size(int x) {

        return -par[find(x)];

    }

};



int main() {

    int N, M;

    cin >> N >> M;

    vector<int> a(N);

    rep(i, N) {

        cin >> a[i]; a[i]--;

    }

    vector<int> pos(N);

    rep(i, N) pos[a[i]] = i;

    UnionFind uf;

    uf.init(N);

    rep(i, M) {

        int x, y; cin >> x >> y;

        x--; y--;

        uf.unite(x, y);

    }

    int ans = 0;

    rep(i, N) {

        if (uf.same(i, pos[i])) ans++;

    }

    cout << ans << endl;

    return 0;

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

using namespace std;



const int mxn = 1e5+2;

vector<int> a1;

vector<int> a2;

vector<int> p(mxn);

bool vis[100001];

vector<int> g[100001];

vector<int> st(mxn);

int cnt = 0;

void dfs(int x){

	vis[x] = 1;

	if(st[x]>0) return;

	st[x] = cnt;

	for(auto to : g[x]){

		if(vis[to]) continue;

		dfs(to);

	}

}



int main(){

	int n,m;

	cin>>n>>m;

	for(int i = 1; i <= n; i++) cin>>p[i];

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

		int a,b;

		cin>>a>>b;

		g[a].push_back(b);

		g[b].push_back(a);

	}



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

		if(!vis[i]){

			cnt++;

			dfs(i);

		}

	}

    int res = 0;

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

		if(st[i]==st[p[i]]) res++;

	}

	 cout<<res;

}

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

using namespace std;



const int mxn = 1e5+1;

vector<int> st(1e5+1);



int fs(int x){

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

	return st[x] = fs(st[x]);

}



void us(int x,int y){

	int px = fs(x);

	int py = fs(y);

	if(px!=py) st[py] = px;

}



int main(){

	int n,m;

	cin>>n>>m;



	vector<int> p(n+1);



	for(int i = 1; i <= n; i++) cin>>p[i];

	for(int i = 1; i <= n; i++) st[i] = i;



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

		int x,y;

		cin>>x>>y;

		us(x,y);

	}

	int res = 0;

	for(int i = 1; i <= n; i++) if(fs(p[i]) == fs(i)) res++;

	cout<<res;

}
// Slower C++ solution:
#include <iostream>

#include <algorithm>

#include <string>

#include <cmath>

#include <vector>

#include <queue>

#include <stack>

#include <utility>

#include <map>

using namespace std;



using ll = long long;



constexpr int limit = 1e5;

int n, m;



class V{

public:

  int tag;

  vector<V*> to;

};



int type[limit+1];

bool visited[limit+1];

int x[limit+1], y[limit+1];

V graph[limit+1];



void bfs(int, int);



int main(){

  cin >> n >> m;

  int p[n+1];

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

    cin >> p[i];

    graph[i].tag = i;

  }



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

    cin >> x[i] >> y[i];

    graph[x[i]].to.push_back(&graph[y[i]]);

    graph[y[i]].to.push_back(&graph[x[i]]);

  }



  int cnt=0;

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

    if(!visited[i]){

      bfs(i, cnt);

      cnt++;

    }

  }



  int ans = n;

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

    if(type[i] != type[p[i]]) ans--;

  }



  cout << ans << endl;



  return 0;

}



void bfs(int s, int t){

  type[s] = t;

  visited[s] = true;

  for(int i=0; i<graph[s].to.size(); i++){

    int nx = graph[s].to[i]->tag;

    if(!visited[nx]){

      bfs(nx, t);

    }

  }

}


// Faster C++ solution for the same problem (measured speedup: 4.337415219209001x):
#include <iostream>

using namespace std;



/*

union_find class:

  int n;

  int *par, *rank;



  method: 

    union_find(int n);

    int find(int x);

    void unite(int x, int y);

    bool same(int x, int y);

    void print();

*/





class union_find{

public:

  int n;

  int *par, *rank;



  union_find(int n){

    this-> n = n;

    par = new int[n];

    rank = new int[n];

    init();

  }

  

  int find(int x){

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

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

  }



  void unite(int x, int y){

    x = find(x);

    y = find(y);



    if(x == y) return;



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

      par[x] = y;

    }else{

      par[y] = x;

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

    }

  }



  bool same(int x, int y){

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

  }



  int solve(){

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



    }

  }



  void print(){

    cout << "---------------" << endl;

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

      cout << "par " << i << " : " << par[i] << endl;

    }

    cout << "---------------" << endl;

  }



private:

  void init(){

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

      par[i] = i;

      rank[i] = 1;

    }

  }

};



int main(){

  int n, m; cin >> n >> m;

  union_find uf(n);

  int v[n];

  for(int i=0; i<n; i++) cin >> v[i];



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

    int x, y;

    cin >> x >> y;

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

  }  



  int cnt = 0;

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

    if(uf.same(i, v[i]-1)) cnt++;

  }



  cout << cnt << endl;

  /* uf.print(); */

  

  return 0; 

}
// Slower C++ solution:
#include <iostream>

#include <algorithm>

#include <string>

#include <cmath>

#include <vector>

#include <queue>

#include <stack>

#include <utility>

#include <map>

using namespace std;



using ll = long long;



constexpr int limit = 1e5;

int n, m;



class V{

public:

  int tag;

  vector<V*> to;

};



int type[limit+1];

bool visited[limit+1];

int x[limit+1], y[limit+1];

V graph[limit+1];



void bfs(int, int);



int main(){

  cin >> n >> m;

  int p[n+1];

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

    cin >> p[i];

    graph[i].tag = i;

  }



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

    cin >> x[i] >> y[i];

    graph[x[i]].to.push_back(&graph[y[i]]);

    graph[y[i]].to.push_back(&graph[x[i]]);

  }



  int cnt=0;

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

    if(!visited[i]){

      bfs(i, cnt);

      cnt++;

    }

  }



  int ans = n;

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

    if(type[i] != type[p[i]]) ans--;

  }



  cout << ans << endl;



  return 0;

}



void bfs(int s, int t){

  type[s] = t;

  visited[s] = true;

  for(int i=0; i<graph[s].to.size(); i++){

    int nx = graph[s].to[i]->tag;

    if(!visited[nx]){

      bfs(nx, t);

    }

  }

}


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

#define FOR(i, a, b) for(int i=(a); i<(b); i++)

#define REP(i, n) FOR(i, 0, n)

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

#define bit(x) (1L << (x))

using ll = long long;

using namespace std;



class union_find{

    int n_; 

    vector<int> par, rank, size;

    public:

    union_find(int n): n_{n} {

        par.resize(n_);

        rank.resize(n_);

        size.resize(n_);



        REP(i, n_){

            par[i] = i;

            rank[i] = 1;

            size[i] = 1;

        }

    } 



    bool same(int x, int y) {

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

    }



    void unite(int x, int y) {

        x = find(x);

        y = find(y);



        if(x == y) return;



        if(rank[x] > rank[y]){

            par[y] = x;

            size[x] += size[y];

        } else {

            par[x] = y;

            size[y] += size[x];

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

        }

    }



    int find(int x) {

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

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

    }

};



int main() {

    int n, m; cin >> n >> m;

    vector<int> p(n);

    union_find uf(n);



    REP(i, n){

        cin >> p[i];

        --p[i];

    }



    REP(i, m) {

        int x, y; cin >> x >> y;

        --x; --y;

        uf.unite(x, y);

    }



    int ans = 0;

    

    REP(i, n) {

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

    }



    cout << ans << endl;

    

    return 0;

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



#define INF 1e9

#define llINF 1e18

#define MOD 1e9+7

#define pb push_back

#define mp make_pair 

#define F first

#define Nodes 100100

#define S second

#define ll long long

using namespace std;

//union find{

#define MAX_N 100100

int par[MAX_N]; // 親

int Rank[MAX_N]; // 木の深さ



void init(int n){

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

    par[i] = i;

    Rank[i] = 0;

  }

}

// 木の根を求める

int find(int x){

  if(par[x] == x)

    return x;

  else

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

}

// xとyの属する集合を併合

void unite(int x, int y){

  x = find(x);

  y = find(y);

  if(x == y) return;

  

  // 木の高さが高い方を代表ノードにする

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

    par[x] = y;

  }else{

    par[y] = x;

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

  }

}

// xとyが同じ集合ならtrue

bool same(int x,int y){

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

}

int main(){

  int n,m;cin>>n>>m;

  vector<int>num(n);

  init(100010);

  for(int i=0;i<n;i++)cin>>num[i];

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

    int a,b;cin>>a>>b;

    unite(a,b);

  }

  ll ans=0;

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

    if(find(num[i])==find(i+1))ans++;

  }

  cout<<ans<<endl;

  return 0;

}


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

#define INF 1e9

#define llINF 1e18

#define MOD 1000000007

#define pb push_back

#define mp make_pair 

#define F first

#define S second

#define ll long long

#define vi vector<ll>

#define vvi vector<vi>

#define BITLE(n) (1LL<<((ll)n))

#define SHIFT_LEFT(n) (1LL<<((ll)n))

#define SUBS(s,f,t) ((s).substr((f),(t)-(f)))

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

using namespace std;

struct UF

{

  vector<int> par;

  vector<int> sz;

  vector<int> rank;

  UF(int n):par(n),sz(n),rank(n){

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

      par[i] = i;sz[i] = 1;rank[i] = 0;

    }

  }

  int find(int x) {

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

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

  }

  void merge(int x, int y) {

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

    if (x == y) return;

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

      par[x] = y;

      sz[y] += sz[x];

    }

    else{

      par[y] = x;

      sz[x] += sz[y];

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

    }

  }

  bool same(int x, int y) { return find(x) == find(y); }

  int size(int n){return sz[find(n)];}

};



int main(){

  cin.tie(0);

  ios::sync_with_stdio(false);

  ll n,m;cin>>n>>m;

  UF uni(n);

  vi A(n);

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

    cin>>A[i];

    A[i]--;

  }

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

    ll a,b;cin>>a>>b;

    a--;b--;

    uni.merge(a,b);

  }

  ll ans = 0;

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

    ans += (uni.same(i,A[i]));

  }

  cout<<ans<<endl;

  return 0;

}