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 (Python):
import itertools
from collections import deque,defaultdict,Counter
from itertools import accumulate
import bisect
from heapq import heappop,heappush
from fractions import gcd
from copy import deepcopy
import math
import queue


Mod = 1000000007
import sys

sys.setrecursionlimit(100000) 
  
def sieve_of_eratosthenes(n):
    if not isinstance(n,int):
        raise TypeError("n is not int")
    if n<2:
        raise ValueError("n is not effective")
    prime = [1]*(n+1)
    for i in range(2,int(math.sqrt(n))+1):
        if prime[i] == 1:
            for j in range(2*i,n+1):
                if j%i == 0:
                    prime[j] = 0
    res = []
    for i in range(2,n+1):
        if prime[i] == 1:
            res.append(i)
    return res

def factorial(i):
    if i == 1:
        return 1
    else:
        return i*factorial(i-1)
 
class UnionFind:
    def __init__(self,n):
        self.parent = [i for i in range(n+1)]
        self.rank = [0 for i in range(n+1)]
    
    def findroot(self,x):
        if x == self.parent[x]:
            return x
        else:
            y = self.parent[x]
            y = self.findroot(self.parent[x])
            return y
    
    def union(self,x,y):
        px = self.findroot(x)
        py = self.findroot(y)
        if px < py:
            self.parent[py] = px
        else:
            self.parent[px] = py
 
    def same_group_or_no(self,x,y):
        return self.findroot(x) == self.findroot(y)




def main(): 
    n,m = map(int,input().split())
    p = list(map(int,input().split()))
    xy = [list(map(int,input().split())) for i in range(m)]
    un = UnionFind(n)
    ans = 0
    for i in range(m):
        un.union(xy[i][0]-1,xy[i][1]-1)
    for i in range(n):
        if un.same_group_or_no(i,p[i]-1):
            ans += 1
    print(ans)
if __name__ == "__main__":
    main()

Solution (Python):
class UnionFind():
    def __init__(self,n):
        self.n=n
        self.root=[-1]*n
        self.rank=[-1]*n

    def Find_Root(self,x):
        if self.root[x]<0:return x
        else:
            self.root[x]=self.Find_Root(self.root[x])
            return self.root[x]

    def Unite(self,x,y):
        x=self.Find_Root(x)
        y=self.Find_Root(y)

        if x==y:return
        elif self.rank[x]>self.rank[y]:
            self.root[x] +=self.root[y]
            self.root[y]=x
        else:
            self.root[y] +=self.root[x]
            self.root[x]=y
            if self.rank[x]==self.rank[y]:
                self.rank[y] +=1

    def isSameGroup(self,x,y):
        return self.Find_Root(x)==self.Find_Root(y)

    def Count(self,x):
        return -self.root[self.Find_Root(x)]

    def members(self,x):
        root=self.Find_Root(x)
        return [i for i in range(self.n) if self.Find_Root(i)==root]

    def address(self):
        return[i for i,j in enumerate(self.root) if j<0]

    def group_members(self):
        return {i: self.members(i) for i in self.address()}

    def size(self,x):
        return -self.root[self.Find_Root(x)]


n,m=map(int,input().split())
P=list(map(int,input().split()))
XY=[list(map(int,input().split())) for i in range(m)]
UnionFind=UnionFind(n)

for x,y in XY:
    UnionFind.Unite(x-1,y-1)

print(sum([UnionFind.isSameGroup(i,j-1) for i,j in enumerate(P)]))

Solution (Python):
class UnionFind:
    def __init__(self, n):
        
        self.par = [i for i in range(n+1)]
        self.rank = [0] * (n+1)
        self.size = [1] * (n+1)
    def find(self, x):
        
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]
    def same_check(self, x, y):
        
        return self.find(x) == self.find(y)
    def union(self, x, y):
        
        x = self.find(x)
        y = self.find(y)
        if self.rank[x] < self.rank[y]:
            self.par[x] = y
            self.size[y] += self.size[x]
            self.size[x] = 0
        elif self.rank[x] > self.rank[y]:
            self.par[y] = x
            self.size[x] += self.size[y]
            self.size[y] = 0
        else:
            self.rank[x] += 1
            self.par[y] = x
            self.size[x] += self.size[y]
            self.size[y] = 0
    def getsize(self, x):
        p = self.find(x)
        return self.size[p]
n, m = map(int, input().split())
p = list(map(int, input().split()))
G = UnionFind(n)
for i in range(m):
    x,y = map(int, input().split())
    G.union(x,y)
ans = 0
for i in range(1,n+1):
    if G.same_check(p[i-1], i):
        ans += 1
print(ans)

Solution (Python):
class UnionFind():
    
    def __init__(self, n):
        self.n = n
        self.parents = [-1]*n  

    
    def find(self, x):  
        if self.parents[x] < 0:  
            return x
        else:
            
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    
    def union(self, x, y):
        x = self.find(x)  
        y = self.find(y)  
        if x == y:
            return  

        
        if self.parents[x] > self.parents[y]:
            
            
            x, y = y, x

        self.parents[x] += self.parents[y]  
        self.parents[y] = x  

    
    def size(self, x):
        
        return -self.parents[self.find(x)]

    
    def same(self, x, y):
        
        return self.find(x) == self.find(y)

    
    def members(self, x):
        root = self.find(x)  
        
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_counts(self):
        
        return len(self.roots())

    def all_group_members(self):
        
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


N, M = map(int, input().split())
P = list(map(lambda x: int(x)-1, input().split()))
uf = UnionFind(N)
for _ in range(M):
    x, y = map(lambda x: int(x)-1, input().split())
    uf.union(x, y)

ans = 0
for i in range(N):
    if uf.same(i, P[i]):
        ans += 1
print(ans)

Solution (Python):
import sys
input=sys.stdin.readline
def main():
  n,m=map(int,input().split())
  p=list(map(int,input().split()))
  xy=[list(map(int,input().split())) for i in range(m)]
  class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)
  uf=UnionFind(n)
  for i in range(m):
    uf.union(p[xy[i][0]-1]-1,p[xy[i][1]-1]-1)
  ans=0
  for i in range(n):
    if uf.same(i,p[i]-1):
      ans+=1
  print(ans)
if __name__=='__main__':
  main()

Solution (Python):
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time,copy,functools
from collections import deque

sys.setrecursionlimit(10**7)
inf = 10**20
mod = 10**9 + 7

DR = [1, -1, 0, 0]
DC = [0, 0, 1, -1]

def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI_(): return [int(x)-1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def I(): return int(sys.stdin.readline())
def F(): return float(sys.stdin.readline())
def S(): return input()

class UnionFind():
    def __init__(self, n):
        self.parent = [i for i in range(n)]

    def unite(self, a, b):
        
        r1 = self.root(a)
        r2 = self.root(b)
        if r1 == r2:
            return
        self.parent[r2] = r1

    def root(self, a):
        if self.parent[a] == a:
            return a
        par = self.root(self.parent[a])
        self.parent[a] = par
        return par

    def sameRoot(self, a, b):
        return self.root(a) == self.root(b)

    def reroot(self):
        for ix, a in enumerate(self.parent):
            self.parent[ix] = self.root(a)
        return

def main():
    N, M = LI()
    P = LI_()
    X, Y = [], []
    uf = UnionFind(N)
    for _ in range(M):
        x, y = LI_()
        uf.unite(x, y)
    cnt = 0
    for ix, p in enumerate(P):
        if uf.sameRoot(ix, P[ix]):
            cnt += 1
    print(cnt)
main()

Solution (Python):
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time,copy,functools
from collections import deque

sys.setrecursionlimit(10**7)
inf = 10**20
mod = 10**9 + 7

DR = [1, -1, 0, 0]
DC = [0, 0, 1, -1]

def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI_(): return [int(x)-1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def I(): return int(sys.stdin.readline())
def F(): return float(sys.stdin.readline())
def S(): return input()

class UnionFind():
    def __init__(self, n):
        self.parent = [i for i in range(n)]

    def unite(self, a, b):
        
        r1 = self.root(a)
        r2 = self.root(b)
        if r1 == r2:
            return
        self.parent[r2] = r1

    def root(self, a):
        if self.parent[a] == a:
            return a
        par = self.root(self.parent[a])
        self.parent[a] = par
        return par

    def reroot(self):
        for ix, a in enumerate(self.parent):
            self.parent[ix] = self.root(a)
        return

def main():
    N, M = LI()
    P = LI_()
    X, Y = [], []
    uf = UnionFind(N)
    for _ in range(M):
        x, y = LI_()
        uf.unite(x, y)
    uf.reroot()
    groups = collections.defaultdict(set)
    for i, par in enumerate(uf.parent):
        groups[par].add(i)

    cnt = 0
    for _, g in groups.items():
        for ix in g:
            if P[ix] in g:
                cnt += 1
    print(cnt)
main()

Solution (Python):
import sys
input = sys.stdin.buffer.readline
N,M = list(map(int,input().split()))
p = [i-1 for i in map(int,input().split())]
alr = [False for i in range(N)]
xy = [[] for i in range(N)]
for i in range(M):
    x,y = map(int,input().split())
    x -= 1
    y -= 1
    xy[x].append(y)
    xy[y].append(x)
count = 0

for i in range(N):
    if (not alr[i]) and (xy[i]):
        alr[i] = True
        stack = [i]
        numlist = set()
        numlist.add(i)
        while stack:
            j = stack.pop()
            for k in xy[j]:
                if not alr[k]:
                    alr[k] = True
                    stack.append(k)
                    numlist.add(k)
        indlist = set([p[i] for i in numlist])
        count += len(numlist & indlist)
    else:
        if (not alr[i]) and p[i] == i:
            count += 1
print(count)

Solution (Python):

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


n, m = map(int, input().split())
p = list(map(int, input().split()))
s = [list(map(int, input().split())) for i in range(m)]

uf = UnionFind(n)
for x, y in s:
    uf.union(x-1, y-1)

ans = 0
for i in range(n):
    if uf.same(i, p[i]-1):
        ans += 1
print(ans)

Solution (Python):
import sys
input = sys.stdin.buffer.readline

def main():
    N,M = map(int,input().split())
    p = list(map(int,input().split()))
    
    I = [i for i in range(N)]
    def root(x):
        if x == I[x]:
            return x
        I[x] = root(I[x])
        return I[x]

    for _ in range(M):
        x,y = map(int,input().split())
        a = root(x-1)
        b = root(y-1)
        if a != b:
            I[b] = a

    c = 0
    for i in range(N):
        if root(p[i]-1) == root(i):
            c += 1
            
    print(c)
    
if __name__ == "__main__":
    main()

Solution (Python):
class UnionFind():
    def __init__(self, N):
        self.par = [i for i in range(N)]
        self.rank = [0 for _ in range(N)]
        self.size = [1 for _ in range(N)]

    def find(self, x):
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]
    
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x != y:
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            elif self.rank[x] < self.rank[y]:
                x, y = y, x
            self.par[y] = x
            self.size[x] += self.size[y]

    def is_same(self, x, y):
        return self.find(x) == self.find(y)
    
    def get_size(self, x):
        x = self.find(x)
        return self.size[x]

N, M = map(int, input().split())
P = list(map(int, input().split()))
uf = UnionFind(N)
for i in range(M):
    x, y = map(int, input().split())
    x, y = x-1, y-1
    uf.union(x, y)

ans = 0
for i in range(N):
    if uf.is_same(i, P[i]-1):
        ans += 1

print(ans)

Solution (Python):
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
 
n,m = map(int,readline().split())
p = list(map(int,readline().split()))




def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True


def same(x,y):
    return find(x) == find(y)


def size(x):
    return -par[find(x)]


def members(x):
    root = find(x)
    return [i for i in range(n) if find(i) == root]


def roots():
    return [i for i,x in enumerate(par) if x < 0]


def group_count():
    return len(roots())


def all_group_members():
    return {r: members(r) for r in roots()}



par = [-1]*n

"""
uniteでまとめ、findで見つける。
n(要素数)だけ最初に付け加えること。
"""

for i in range(m):
    x,y = map(int,readline().split())
    unite(x-1,y-1)

ans = 0

for i in range(n):
    if same(p[i]-1,i):
        ans += 1

print(ans)

Solution (Python):
n,m = map(int, input().split())
p = list(map(int, input().split()))
a = [list(map(int, input().split())) for i in range(m)]


class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

uf = UnionFind(n)

for i in range(m):
    uf.union(a[i][0]-1, a[i][1]-1)


count=0
for i in range(n):
    if p[i]-1==i:
        count+=1
    else:
        if uf.same(p[i]-1,i):
            count+=1
print(count)

Solution (Python):
n,m=map(int,input().split())
p=list(map(int,input().split()))
pa=list(range(n))
def find(u):
  if u!=pa[u]:pa[u]=find(pa[u])
  return pa[u]
for i in range(m):
  a,b=map(int,input().split())
  a=find(a-1)
  b=find(b-1)
  if a!=b:pa[a]=b
c=0
for i in range(n):
  if find(p[i]-1)==find(i):c+=1
print(c)

Solution (Python):
import sys
input = sys.stdin.readline
 
class Unionfind:
    def __init__(self, n):
        self.par = [-1]*n
        self.rank = [1]*n
    
    def root(self, x):
        p = x
        
        while not self.par[p]<0:
            p = self.par[p]
        
        while x!=p:
            tmp = x
            x = self.par[x]
            self.par[tmp] = p
        
        return p
    
    def unite(self, x, y):
        rx, ry = self.root(x), self.root(y)
        
        if rx==ry: return False
        
        if self.rank[rx]<self.rank[ry]:
            rx, ry = ry, rx
        
        self.par[rx] += self.par[ry]
        self.par[ry] = rx
    
        if self.rank[rx]==self.rank[ry]:
            self.rank[rx] += 1
    
    def is_same(self, x, y):
        return self.root(x)==self.root(y)
    
    def count(self, x):
        return -self.par[self.root(x)]

N, M = map(int, input().split())
p = list(map(lambda x: x-1, map(int, input().split())))
uf = Unionfind(N)

for _ in range(M):
    x, y = map(int, input().split())
    uf.unite(p[x-1], p[y-1])

ans = 0

for i in range(N):
    if uf.is_same(p[i], i):
        ans += 1

print(ans)

Solution (Python):
from collections import defaultdict
def main():
    n,m = map(int,input().split())
    p = list(map(int,input().split()))
    xy = sorted([tuple(map(int,input().split())) for _ in range(m)])
    d = defaultdict(list)
    for i in xy:
        d[i[0]].append(i[1])
        d[i[1]].append(i[0])
    searched = [False]*n
    c = 0
    graph = []
    allset = set(range(1,n+1))
    while allset:
        xxx = allset.pop()
        pool = set([xxx])
        searched[xxx-1] = True
        g = [xxx]
        gap = g.append
        pad = pool.add
        while pool:
            s = pool.pop()
            tmp = set(d[s])
            dif = tmp&allset
            dad = dif.add
            for i in dif:
                if searched[i-1] is False:
                    dad(i)
                    searched[i-1] = True
                    c += 1
                    gap(i)
                    allset.discard(i)
                    pad(i)
        graph.append(tuple(g))
    ans = 0
    for i in graph:
        ppp = set([p[j-1] for j in i])
        ans += len(ppp&set(i))
    print(ans)
    
if __name__ == '__main__':
    main()

Solution (Python):
class UnionFind:
    def __init__(self, N):
        self.N = N
        self.parents = [-1] * N

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.N) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

N, M = map(int, input().split())
P = list(map(int, input().split()))
UF = UnionFind(N)
for i in range(N):
    P[i] -= 1
for _ in range(M):
    x, y = map(int, input().split())
    x-=1
    y-=1
    UF.union(x, y)

print(sum(UF.same(i,p) for i,p in enumerate(P)))

Solution (Python):
N, M = map(int, input().split())
P = list(map(int, input().split()))
for i in range(N):
    P[i] -= 1
T = [[] for _ in range(N)]
for _ in range(M):
    x, y = map(int, input().split())
    x-=1
    y-=1
    T[x].append(y)
    T[y].append(x)

s1 = set()
def dfs(x):
    s1.add(x)
    s2 = set([x])
    stack = [x]
    while stack:
        u = stack.pop()
        for v in T[u]:
            if v not in s1 and v not in s2:
                s1.add(v)
                s2.add(v)
                stack.append(v)
    return s2

ans = 0
for i in range(N):
    if i in s1:
        continue
    I = dfs(i)
    PI = set(P[i] for i in I)
    ans += len(I.intersection(PI))
print(ans)

Solution (Python):
class UnionFind():
    def __init__(self, n):
        self.parent = [-1 for _ in range(n)]
        

    def find(self, x):
        if self.parent[x] < 0:
            return x
        else:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]

    def unite(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return False
        else:
            if self.size(x) < self.size(y):
                x, y = y, x
            self.parent[x] += self.parent[y]
            self.parent[y] = x

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        x = self.find(x)
        return -self.parent[x]

    def is_root(self, x):
        return self.parent[x] < 0

n, m = map(int, input().split())
p = list(map(int, input().split()))
pair_list = []
count = 0
for i in range(m):
    array = list(map(int,input().split()))
    array[0] -=1 ; array[1] -= 1
    pair_list.append(array)

uf = UnionFind(len(p))

for i in range(m):
    uf.unite(pair_list[i][0], pair_list[i][1])

for i in range(n):
    uf.find(i)

for i in range(n):
    if p[i] == i+1:
        count += 1
    else:
        if uf.same(p[i]-1, p[p[i]-1]-1) is True:
            count += 1
        else:
            continue
print(count)

Solution (Python):
import sys
input = sys.stdin.readline

class UnionFind():
    def __init__(self, n):
        self.parent = [-1 for _ in range(n)]
        

    def find(self, x):
        if self.parent[x] < 0:
            return x
        else:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]

    def unite(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return False
        else:
            if self.size(x) < self.size(y):
                x, y = y, x
            self.parent[x] += self.parent[y]
            self.parent[y] = x

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        x = self.find(x)
        return -self.parent[x]

    def is_root(self, x):
        return self.parent[x] < 0


N,M = map(int,input().split())
p = list(map(int,input().split()))
uf = UnionFind(N)
for i in range(M):
    x,y = map(int,input().split())
    uf.unite(x-1,y-1)

ans = 0
for i in range(N):
    if p[i]-1 == i:
        ans += 1
    else:
        if uf.same(p[i]-1,i):
            ans += 1
print(ans)

Solution (Python):
class UnionFind():
    def __init__(self, n):
        self.parent = [-1 for _ in range(n)]
        

    def find(self, x):
        if self.parent[x] < 0:
            return x
        else:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]

    def unite(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return False
        else:
            if self.size(x) < self.size(y):
                x, y = y, x
            self.parent[x] += self.parent[y]
            self.parent[y] = x

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        x = self.find(x)
        return -self.parent[x]

    def is_root(self, x):
        return self.parent[x] < 0


N,M = map(int,input().split())
p = list(map(int,input().split()))
uf = UnionFind(N)
for i in range(M):
    x,y = map(int,input().split())
    uf.unite(x-1,y-1)

ans = 0
for i in range(N):
    if p[i]-1 == i:
        ans += 1
    else:
        if uf.same(p[i]-1,i):
            ans += 1
print(ans)

Solution (Python):
import sys
input = sys.stdin.readline
class UnionFind(object):
    def __init__(self, n=1):
        self.par = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = [1 for _ in range(n)]

    def find(self, x):
        """
        x が属するグループを探索
        """
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]

    def union(self, x, y):
        """
        x と y のグループを結合
        """
        x = self.find(x)
        y = self.find(y)
        if x != y:
            if self.rank[x] < self.rank[y]:
                x, y = y, x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            self.par[y] = x
            self.size[x] += self.size[y]

    def is_same(self, x, y):
        """
        x と y が同じグループか否か
        """
        return self.find(x) == self.find(y)

    def get_size(self, x):
        """
        x が属するグループの要素数
        """
        x = self.find(x)
        return self.size[x]

N,M=map(int,input().split())
p=list(map(int,input().split()))

uf=UnionFind(N)
for i in range(M):
    x,y=map(int,input().split())
    uf.union(x-1,y-1)

cnt=0
for i in range(N):
    if uf.is_same(i,p[i]-1):
        cnt+=1
print(cnt)

Solution (Python):

from collections import defaultdict
class UnionFind:
    def __init__(self, n):
        class KeyDict(dict):
            
            def __missing__(self,key):
                self[key] = key
                return key
        self.parent = KeyDict()
        self.rank = defaultdict(int)
        self.weight = defaultdict(int)

    
    def find(self, x):
        if self.parent[x] == x:
            return x
        else:
            
            
            y = self.find(self.parent[x])           
            self.weight[x] += self.weight[self.parent[x]]   
            self.parent[x] = y      
            return self.parent[x]

    
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        
        if self.rank[x] < self.rank[y]:
            self.parent[x] = y
        else:
            self.parent[y] = x
        
        if self.rank[x] == self.rank[y]:
            self.rank[x] += 1

    
    def weighted_union(self, x, y, w):
        
        px = self.find(x)
        py = self.find(y)
        
        
        if self.rank[px] < self.rank[py]:
            self.parent[px] = py
            self.weight[px] = - w - self.weight[x] + self.weight[y]
        else:
            self.parent[py] = px
            self.weight[py] =  w + self.weight[x] - self.weight[y]
        if self.rank[px] == self.rank[py]:
            self.rank[px] += 1
        return 0

    
    def judge(self, x, y):
        return self.find(x) == self.find(y)



n, m = map(int, input().split())
ps = list(map(int, input().split()))

"""    
Unionfindで、自由に移動できるindexを同定
その中で、indexと数字がおなじになるものを同定
"""
uf = UnionFind(n)
for i in range(m):
    x,y = map(int, input().split())
    x -= 1
    y -= 1
    if not uf.judge(x,y):
        uf.union(x,y)

ps = [p-1 for p in ps]

ans = 0
for i,p in enumerate(ps):
    if uf.judge(i,p):
        ans += 1
        
print(ans)

Solution (Python):
class UnionFind():
   def __init__(self, n):
       self.n = n
       self.parents = [-1] * n

   def find(self, x):
       if self.parents[x] < 0:
           return x
       else:
           self.parents[x] = self.find(self.parents[x])
           return self.parents[x]

   def union(self, x, y):
       x = self.find(x)
       y = self.find(y)

       if x == y:
           return

       if self.parents[x] > self.parents[y]:
           x, y = y, x

       self.parents[x] += self.parents[y]
       self.parents[y] = x

   def size(self, x):
       return -self.parents[self.find(x)]

   def same(self, x, y):
       return self.find(x) == self.find(y)

   def members(self, x):
       root = self.find(x)
       return [i for i in range(self.n) if self.find(i) == root]

   def roots(self):
       return [i for i, x in enumerate(self.parents) if x < 0]

   def group_count(self):
       return len(self.roots())

   def all_group_members(self):
       return {r: self.members(r) for r in self.roots()}

   def __str__(self):
       return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


n,m = map(int,input().split())
pl = list(map(int,input().split()))
uf = UnionFind(n)
for _ in range(m):
   x,y = map(int,input().split())
   uf.union(x-1,y-1)
ans = 0
for idx,p in enumerate(pl):
   ans += uf.same(p-1,idx)
print(ans)