#include <iostream>

using namespace std;

typedef struct dlobj {
  struct dlobj *prev;
  struct dlobj *next;
  int key;
} dlobj;

typedef struct {
  dlobj *nil;
} dlist;

typedef struct {
  int n;
  int m;
  dlist **E;
} graph;

int *A;
dlist *Q;

void check(void *y)
{
  if (y==NULL) {
    printf("Not enough memory.\n");
    exit(1);
  }
}

dlobj *dlobj_new(int key)
{
  dlobj *X;
  X= new dlobj;
  check(X);
  X->prev=X;
  X->next=X;
  X->key=key;
  return X;
}

dlist *dlist_new(void)
{
  dlist *L;
  L=new dlist;
  check(L);
  dlobj *X;
  X=dlobj_new(0);
  L->nil=X;
  return L;
}

dlobj *dlist_search(dlist *L, int k)
{
  dlobj *x=L->nil->next;  //L->nilが先頭の（意味のない）slobj
  while (x!=L->nil) {
    if (x->key==k) return x;
    x=x->next;
  }
  return NULL;
}

void enqueue(dlist *L, dlobj *x) //末尾に追加したい
{
  x->prev=L->nil->prev;
  L->nil->prev->next=x;
  L->nil->prev=x;
  x->next=L->nil;
}

dlobj *dequeue(dlist *L)
{
  dlobj *X;
  X=L->nil->next;
  L->nil->next=X->next;
  X->next->prev=L->nil;
  //Xのnext,prevは変更なしで、リストからは削除
  return X;
}

void dlobj_delete(dlobj *X)
{
  delete X;
}

void dlist_delete(dlist *L)
{
 while (1) {
  dlobj *X;
  X=L->nil->next;
  L->nil->next=X->next;
  if (X==L->nil) {
   dlobj_delete(X);
   break;
  }
  dlobj_delete(X);
 }
 delete L;
}

void graph_delete(graph *G)
{
 int i;
 for (i=0;i<=G->n;i++){
  dlist_delete(G->E[i]);
 }
 delete[] G->E;
 delete G;
}

graph *graph_new(int n,int m) {
  graph *G;
  G=new graph;
  check(G);
  G->n=n;
  G->m=m;
  G->E=new dlist *[n+1]; //indexを1からnとしたいため
  check(G->E);
  int i;
  for (i=0;i<=n;i++){
    G->E[i]=dlist_new();
    check(G->E[i]);
  }
  return G;
}

dlobj *graph_firstedge(graph *G, int i)
{
  if (G->E[i]->nil->next==G->E[i]->nil) return NULL;
  else return G->E[i]->nil->next;
}

dlobj *graph_nextedge(graph *G, int i, dlobj *e)
{
  if (e->next==G->E[i]->nil) return NULL;
  else return e->next;
}

graph *read_graph(int n, int m)
{
  int i,j,x,y;
  graph *G;
  G=graph_new(n, m);
  for (i=0;i<m;i++){
    cin >> x >> y;
    dlobj *X;
    X=dlobj_new(y);
    G->E[x]->nil->prev->next=X;
    X->prev=G->E[x]->nil->prev;
    G->E[x]->nil->prev=X;
    X->next=G->E[x]->nil;
    //無向グラフの場合は下記も
    dlobj *Y;
    Y=dlobj_new(x);
    G->E[y]->nil->prev->next=Y;
    Y->prev=G->E[y]->nil->prev;
    G->E[y]->nil->prev=Y;
    Y->next=G->E[y]->nil;
  }
  return G;
}

dlist *enqueue2(dlist *L,graph *G, int s,int d)
{
  dlobj *X;
  X=graph_firstedge(G, s);
  while (1){
    if (X==NULL) break;
    if (A[X->key -1]==0) {  //Gのsから出ている枝に対し, フラグが立っていなければ枝をLに追加
      dlobj *Y;
      Y=dlobj_new(X->key);
      enqueue(L, Y);
      A[X->key -1]=d;
    }
    //if (X->key==t) break;
    X=graph_nextedge(G, s, X);
  }
  return L;
}

int main() {
  int N,M;
  int i,j;
  cin >> N >> M;
  int p[N+1];
  for (i=1;i<=N;++i) {
    cin >> p[i];
  }
  graph *G;
  G=read_graph(N, M);

  A=new int[G->n];
  for (i=0;i<G->n;i++) {
    A[i]=0;
  }
  Q=dlist_new();
  check(Q);

  int d=1;
  for (i=1;i<=G->n;++i) {
    if (A[i-1]==0) {
      A[i-1]=d;
      dlobj *X;
      X=dlobj_new(i);
      enqueue(Q,X);
      for (j=1;j<=G->n;j++) { //このループは本来はwhile？
        if (X==Q->nil) break;
        Q=enqueue2(Q, G, X->key,d);
        X=X->next;
      }
      d++;
    }
  }
  dlist_delete(Q);
  graph_delete(G);
  d-=1;

  int k=0;
  for (i=1;i<=N;++i) {
    if (A[p[i]-1] == A[i-1]) {
      k++;
    }
  }
  delete[] A;
  cout << k << endl;
  return 0;
}


Measured memory_bytes: 17408