Problem:
Score : 400 points

Problem Statement

We have a permutation of the integers from 1 through N, p_1, p_2, .., p_N.
We also have M pairs of two integers between 1 and N (inclusive), represented as (x_1,y_1), (x_2,y_2), .., (x_M,y_M).
AtCoDeer the deer is going to perform the following operation on p as many times as desired so that the number of i (1 ≤ i ≤ N) such that p_i = i is maximized:

Choose j such that 1 ≤ j ≤ M, and swap p_{x_j} and p_{y_j}.

Find the maximum possible number of i such that p_i = i after operations.

Constraints

2 ≤ N ≤ 10^5

1 ≤ M ≤ 10^5

p is a permutation of integers from 1 through N.

1 ≤ x_j,y_j ≤ N

x_j ≠ y_j

If i ≠ j, \{x_i,y_i\} ≠ \{x_j,y_j\}.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N M
p_1 p_2 .. p_N
x_1 y_1
x_2 y_2
:
x_M y_M

Output

Print the maximum possible number of i such that p_i = i after operations.

Sample Input 1

5 2
5 3 1 4 2
1 3
5 4

Sample Output 1

2

If we perform the operation by choosing j=1, p becomes 1 3 5 4 2, which is optimal, so the answer is 2.

Sample Input 2

3 2
3 2 1
1 2
2 3

Sample Output 2

3

If we perform the operation by, for example, choosing j=1, j=2, j=1 in this order, p becomes 1 2 3, which is obviously optimal.
Note that we may choose the same j any number of times.

Sample Input 3

10 8
5 3 6 8 7 10 9 1 2 4
3 1
4 1
5 9
2 5
6 5
3 5
8 9
7 9

Sample Output 3

8

Sample Input 4

5 1
1 2 3 4 5
1 5

Sample Output 4

5

We do not have to perform the operation.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<list>
#include<memory>

using namespace std;

class UnionFind{
private:
  UnionFind *parent;
  int rank;
  //UnionFind *t_root;
public:
  UnionFind(){
    parent=this;
    rank=0;
  }
  UnionFind *root(UnionFind *x){
    if(x->parent == x){
      return x;
    }
    else{
      //return root(x->parent);
      x->parent=root(x->parent);
      return x->parent;
    }

    return 0;
  }
  int _union(UnionFind *x){
    UnionFind *rx=root(x);
    UnionFind *rt=root(this);

    if(rx->rank > rt->rank) rt->parent = rx;
    else if(rx->rank < rt->rank) rx->parent = rt;
    else if(rx != rt){
      rt->parent = rx;
      rx->rank+=1;
    }

    //rx->parent=rt;
    return 0;
  }
  int find(UnionFind *x){
    if(root(x) == root(this)){
      return 1;
    }
    else{
      return 0;
    }
  }
  void show_root(){
    cout << this->root(this) << endl;
  }
};

void show_v(vector< vector<int> > &v,int n);

int par[100001];
int rnk[100001];

void init(int);
int rt(int);
bool same(int,int);
void unite(int,int);

int main(void){

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

  vector<int> p(n+1);
  vector<int> x(m);
  vector<int> y(m);
  /*
  vector< vector<int> > v(n,vector<int>(n,0));
  */
  int cnt=0;

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

  for(int i=0;i<m;i++){
    cin >> x[i];
    cin >> y[i];
  }

  //show_v(v,n);
  /*
  for(int i=0;i<m;i++){
    v[y[i]-1][x[i]-1] = 1;
  }
  */
  init(n);

  for(int i=0;i<m;i++){
    unite(x[i],y[i]);
    //unite(y[i]-1,x[i]-1);
  }

  for(int i=1;i<n+1;i++){
    if(i == p[i]){
      cnt++;
      continue;
    }
    else{
      cnt += (int)same(i,p[i]);
    }
  }
  cout << cnt << endl;

  //show_v(v,n);
  /*
  vector< UnionFind > graph(n);

  for(int i=0;i<m;i++){
    graph[y[i]-1]._union(&graph[x[i]-1]);
  }

  for(int i=0;i<n;i++){
    //graph[i].show_root();
  }

  for(int i=0;i<n;i++){
    cnt+=graph[i].find(&graph[p[i]-1]);
  }

  cout << cnt << endl;
  */
  //cout << "debug" << endl;

  //for(int i=1;i<n+1;i++) cout << par[i] << endl;

  return 0;
}

void show_v(vector< vector<int> > &v,int n){
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      cout << v[i][j] << " ";
    }
    cout << endl;
  }
  cout << endl;
}

void init(int n){
  for(int i=0;i<n;i++){
    par[i]=i;
    rnk[i]=0;
  }
}
int rt(int x){

  return par[x]==x ? x : par[x]=rt(par[x]);
}
bool same(int x,int y){
  return rt(x) == rt(y);
}
void unite(int x,int y){
  int temp_x;
  int temp_y;
  temp_x=rt(x);
  temp_y=rt(y);

  if(temp_x==temp_y) return ;
  if(rnk[temp_x] < rnk[temp_y]){
    par[temp_x]=temp_y;
  }
  else{
    par[temp_y]=temp_x;
    if(rnk[temp_x] == rnk[temp_y]) rnk[temp_x]++;
  }
}