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):
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 = list(map(int,input().split()))
P = list(map(int,input().split()))
Network = UnionFind(N)

for i in range(M):
    X,Y = list(map(int,input().split()))
    Network.union(X-1, Y-1)

out=0
for i in range(N):
    if Network.find(i)==Network.find(P[i]-1):
        out+=1
print(out)

Solution (Python):
from collections import deque
N, M = map(int, input().split())
P = list(map(int, input().split()))
K = [[] for _ in range(N)]
for i in range(M):
    x, y = map(int, input().split())
    x, y = x-1, y-1
    K[x].append(y)
    K[y].append(x)
used = [0]*N
OK = []
for i in range(N):
    P[i] -= 1
    if i == P[i]:
        OK.append(i)
ans = 0
for i in range(N):
    if used[i] == 0:
        used[i] = 1
        S = deque([i])
        Enable = [i]
        Origin = [P[i]]
        while S:
            t = S.popleft()
            for j in K[t]:
                if used[j] == 0:
                    used[j] = 1
                    Enable.append(j)
                    Origin.append(P[j])
                    S.append(j)
        T_1 = list(set(OK + Enable))
        T_2 = list(set(OK + Origin))
        ans = max(ans, len(T_1) + len(T_2) - len(set(T_1 + T_2)))

print(ans)

Solution (Python):
class UnionFind:
    def __init__(self, n): 
        self.par = [i for i in range(n+1)] 
        self.rank = [0]*(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 union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if self.rank[x] < self.rank[y]:
            self.par[x] = y
        else:
            self.par[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

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

    
    def all_find(self):
        for n in range(len(self.par)):
            self.find(n)

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

uf = UnionFind(n)
for x,y in pab:
    uf.union(x,y)

uf.all_find()

cnt = 0
for i,k in enumerate(p):
    if k == i+1: 
        cnt += 1
    else:
        if uf.same_check(i+1,k):
            cnt += 1
print(cnt)

Solution (Python):
class UnionFind:
    def __init__(self, n): 
        self.par = [i for i in range(n+1)] 
        self.rank = [0]*(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 union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if self.rank[x] < self.rank[y]:
            self.par[x] = y
        else:
            self.par[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

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

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

uf = UnionFind(n)
for x,y in pab:
    uf.union(x,y)

cnt = 0
for i,k in enumerate(p):
    if k == i+1: 
        cnt += 1
    else:
        if uf.same_check(i+1,k):
            cnt += 1
print(cnt)

Solution (Python):
n, m = map(int, input().split())
p = list(map(int, input().split()))

parent = [i + 1 for i in range(n)]
rank = [0 for i in range(n)]

def find(x):
    if parent[x - 1] == x:
        return x
    else:
        parent[x - 1] = find(parent[x - 1])
        return parent[x - 1]

def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return
    if rank[x - 1] < rank[y - 1]:
        parent[x - 1] = y
    else:
        parent[y - 1] = x
        if rank[x - 1] == rank[y - 1]:
            rank[x - 1] += 1

for i in range(m):
    x, y = map(int, input().split())
    unite(x, y)
dic = {}
for i in range(n):
    dic.setdefault(find(i + 1), [set(), set()])
    dic[find(i + 1)][0].add(i + 1)
    dic[find(i + 1)][1].add(p[i])
ans = 0
for i in dic.values():
    ans += len(i[0] & i[1])
print(ans)

Solution (Python):
class UnionFind():
    """
    UnionFindTreeのクラス
    
    Attributes:
    n: int: ノード数
    parents: そのノードが属する木の根を格納, 根の場合は-1

    """
    def __init__(self, n):
        """ノード数nで初期化"""
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        """ノード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が属するグループと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):
        """xが属するグループの要素数を返す"""
        return -self.parents[self.find(x)]

    def same(self, x, y):
        """x, yが同じグループに属するかどうかを返す"""
        return self.find(x) == self.find(y)

    def members(self, x):
        """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):
        """{root: [そのグループの要素リスト]}の辞書を返す"""
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        """printデバッグ用. root: [要素リスト]をstrで返す"""
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())



N,M=map(int,input().split())
p= [0] + list(map(int, input().split()))
uf = UnionFind(N+1)
for _ in range(M):
    x,y=map(int, input().split())
    uf.union(x,y)
ans = 0
for i in range(1, 1+N):
    if p[i]==i:
        ans += 1
    else:
        if uf.same(i, p[i]):
            ans += 1
print(ans)

Solution (Python):
N, M = map(int, input().split())
P = tuple(map(int, input().split()))
A = []
for _ in range(M):
    i, k = map(int, input().split())
    A.append((i-1, k-1))
class Union():
    def __init__(self, n):
        self.para = [-1] * n
    
    def find(self, n):
        if self.para[n] < 0:
            return n
        
        else:
            self.para[n] = self.find(self.para[n])
            return self.para[n]
    
    def union(self, n, m):
        n = self.find(n)
        m = self.find(m)
        if n == m:
            return False
        else:
            if self.para[n] > self.para[m]:
                n, m = m, n
            
            self.para[n] += self.para[m]
            self.para[m] = n
    
    def same(self, n, m):
        return self.find(n) == self.find(m)
ut = Union(N)
for i,k in A:
    ut.union(i, k)
for i in range(N):
    ut.find(i)

cnt = 0
for i in range(N):
    if P[i] == i + 1:
        cnt += 1
    else:
        if ut.same(P[i]-1, i):
            cnt += 1
print(cnt)

Solution (Python):

import sys, math
from itertools import permutations, combinations
from collections import defaultdict, Counter, deque
from math import factorial, gcd
from bisect import bisect_left, bisect_right

sys.setrecursionlimit(10 ** 7)
enu = enumerate
MOD = 10 ** 9 + 7
input = lambda: sys.stdin.readline()[:-1]
pl = lambda x: print(*x, sep="\n")


class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rank = [0] * (n)
        self.size = [1] * (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 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 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 get_size(self, x):
        x = self.find(x)
        return self.size[x]


N, M = map(int, input().split())
p = list(map(int, input().split()))
xy = [list(map(int, input().split())) for _ in range(M)]
uni = UnionFind(N + 1)
for xyi in xy:
    x, y = xyi
    uni.union(x, y)
cnt = 0
for i, pi in enu(p):
    if uni.same_check(i + 1, pi):
        cnt += 1
print(cnt)

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 size(self, x):                                          
        return -self.parents[self.find(x)]

    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())


import sys
input = sys.stdin.readline

N, M = map(int, input().split())
P = list(map(int, input().split()))
U = UnionFind(N)
for _ in range(M):
    a, b = map(int, input().split())
    a, b = a-1, b-1
    U.union(a, b)
res = 0
for i, p in enumerate(P):
    if U.same(p-1,i):
        res += 1
print(res)

Solution (Python):




class UnionFind:

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

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

    def unite(self, u, v):  
        u = self.find(u)
        v = self.find(v)
        if u == v:
            return
        if self.parents[u] > self.parents[v]:  
            u, v = v, u
        self.parents[u] += self.parents[v]
        self.parents[v] = u

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

    def same(self, u, v):  
        return self.find(u) == self.find(v)





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

uf = UnionFind(N + 1)

for _ in range(M):
    x, y = map(int, input().split())
    uf.unite(x, y)
ans = 0
for i in range(1, N + 1):
    if uf.same(p[i - 1], i):
        ans += 1
print(ans)

Solution (Python):
n,n_pairs = map(int,input().split())
p_ls = list(map(int, input().split()))

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):
        '''
        注意：0-idx
        '''
        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(n_pairs):
    x,y = map(int,input().split())
    uf.union(x-1,y-1)

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

Solution (Python):
class uft():
    def __init__(self,n):
        self.p=[ -1 for i in range(n)]
        self.r=[ 1 for i in range(n)]
        
    def find(self,x):
        if(self.p[x]==-1):
            return x
        else:
            self.p[x]=self.find(self.p[x])
            return self.find(self.p[x])
        
    def unite(self,x,y):
        x=self.find(x)
        y=self.find(y)
        if(self.r[x]>self.r[y]):
            tmp=x
            x=y
            y=tmp
            
        if(self.r[x]==self.r[y]):
            self.r[y]+=1
            
        if(x!=y):
            self.p[x]=y
        return
    
n,m=map(int,input().split())
p=list(map(int,input().split()))
for i in range(n):
  p[i]-=1
uf=uft(n)
for i in range(m):
    x,y=map(int,input().split())
    x-=1
    y-=1
    uf.unite(x,y)
ans=0
for i in range(n):
    if(uf.find(i)==uf.find(p[i])):
        ans+=1
        
print(ans)

Solution (Python):
n, m = map(int, input().split())
p = list(map(lambda x: int(x)-1, input().split()))
q = [tuple(map(lambda x: int(x)-1, input().split())) for _ in range(m)]

par = [x for x in range(n)]
rank = [0]*n

def find(x):
  if par[x] == x:
    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
  if rank[x] < rank[y]:
    par[x] = y
  else:
    par[y] = x
    if rank[x] == rank[y]: rank[x] += 1

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

for x, y in q:
  unite(x, y)


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

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

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

def union(x,y):
  fx=find(x)
  fy=find(y)
  if fx!=fy:
    par[fx]=fy
    
for i in range(m):
  a,b=map(int,input().split())
  union(a-1,b-1)
  
ans=0
  
for i in range(n):
  if find(p[i]-1)==find(i):
    ans+=1
    

print(ans)

Solution (Python):
N,M=map(int,input().split())
P=list(map(int,input().split()))
P=[i-1 for i in P]
par=[i for i in range(N)]
size=[1 for i in range(N)]
def find(x):
  if par[x]==x:
    return x
  else:
    par[x]=find(par[x])
    return par[x]
def union(a,b):
  x=find(a)
  y=find(b)
  if x!=y:
    if size[x]<size[y]:
      par[x]=par[y]
      size[y]+=size[x]
    else: 
      par[y]=par[x]
      size[x]+=size[y]
  else:
    return
for i in range(M):
  x,y=map(int,input().split())
  union(x-1,y-1)
count=0
for i in range(N):
  if find(i)==find(P[i]):
    count+=1
print(count)

Solution (Python):



def main():
    n, m = list(map(int, input().split()))
    p = [i-1 for i in list(map(int, input().split()))]

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

    roots = uf.roots()
    sets_dict = {}
    members_dict = {}
    for i in roots:
        sets_dict[i] = set([])
        members_dict[i] = set([])

    for i in range(n):
        root = uf.find(i)
        sets_dict[root].add(p[i])
        members_dict[root].add(i)
        
    
    
    ans = 0
    for i in roots:
        ans += len(sets_dict[i] & members_dict[i])
    print(ans)


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())


if __name__ == "__main__":
    main()

Solution (Python):
import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]




'''
N, M = mi()
P = li()
tmp = []


for i in range(M):
    x, y = mi()
    x, y = x-1, y-1
    if x > y:
        x, y = y, x
    tmp.append([x, y])

xy = []

sorted(tmp, key=lambda x : x[0])
print(tmp)
now = tmp[0][0]
flag = [0] * N
tmp2 = [now]
num = 1
flag[tmp[0][0]] = num
for x, y in tmp:
    if x != now:
        xy.append(tmp2)
        tmp2 = [x]
        now = x
        num += 1
        flag[x] = num
    tmp2.append(y)
    flag[y] = num

if tmp2:
    xy.append(tmp2)

print(flag)
print(xy)

for i in range(N):
'''
class UnionFind:
    def __init__(self, n):
        self.d = [-1]*n
    
    def find(self, x):
        if self.d[x] < 0:
            return x
        else:
            self.d[x] = self.find(self.d[x])
            return self.find(self.d[x])
    
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x==y:
            return False
        if self.d[x] > self.d[y]:
            x, y = y, x
        self.d[x] += self.d[y]
        self.d[y] = x
        return True
    
    def same(self, x, y):
        if self.find(x)==self.find(y):
            return True
        return False
    
    def size(self, x):
        return (-1) * self.d[self.find(x)]

N, M = mi()
P = li()
G = UnionFind(N)
ans = 0

for i in range(M):
    x, y = mi()
    G.unite(x-1, y-1)
    
for i in range(N):
    if G.same(P[i]-1, i):
        ans += 1

print(ans)

Solution (Python):
import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60
MOD = 1000000007


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 main():
    N, M = map(int, readline().split())
    P = [int(s) - 1 for s in readline().split()]
    XY = map(int, read().split())

    uf = UnionFind(N)
    for x, y in zip(*[iter(XY)] * 2):
        uf.union(x - 1, y - 1)

    ans = 0
    for i, p in enumerate(P):
        if i == p or uf.same(i, p):
            ans += 1

    print(ans)
    return


if __name__ == '__main__':
    main()

Solution (Python):
import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60
MOD = 1000000007


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 main():
    N, M = map(int, readline().split())
    P = [int(s) - 1 for s in readline().split()]
    XY = map(int, read().split())

    uf = UnionFind(N)
    for x, y in zip(*[iter(XY)] * 2):
        uf.union(x - 1, y - 1)

    Q = [0] * N
    for i, p in enumerate(P):
        Q[p] = i

    ans = 0
    for i, p in enumerate(P):
        if i == p or uf.same(i, Q[i]):
            ans += 1

    print(ans)
    return


if __name__ == '__main__':
    main()

Solution (Python):
n, m = map(int, input().split())
p=list(map(int, input().split()))

par=[-1]*n

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

def union(x, y):
    p,q=find(x), find(y)
    if p==q:
        return
    if p > q:
        p,q=q,p
    par[p]+=par[q]
    par[q]=p

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

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

ans=0

for i in range(n):
    if p[i]==i+1:
        ans+=1
        continue
    if same(i, p[i]-1):
        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 same(self, x, y):
        return self.find(x) == self.find(y)


N,M = map(int,input().split())
P = [0]+list(map(int,input().split()))

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

ans = 0

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

print(ans)

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

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

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

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

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

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


def main():
    n, m = map(int, input().split())
    p = list(map(int, 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.is_same(i, p[i] - 1):
            ans += 1
    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):


class UnionFindTree():

    def __init__(self, n):
        
        self.n  = n
        
        self.root = [-1] * (n+1)
        
        self.rank = [1] * (n+1)

    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 is_same(self,x,y):
        return self.find_root(x) == self.find_root(y)

    def count_node(self,x):
        return -1 * self.root[self.find_root(x)]


n, m = map(int, input().split())
uft = UnionFindTree(n)

p_arr = list(map(int, input().split()))

for _ in range(m):
    x, y = map(int, input().split())
    uft.unite(x, y)

ans = 0
for index, num in enumerate(p_arr):
    if uft.is_same(index+1, num):
        ans += 1
print(ans)

Solution (Python):
import sys
sys.setrecursionlimit(10**9)

def mi(): return map(int,input().split())
def ii(): return int(input())
def isp(): return input().split()
def deb(text): print("-------\n{}\n-------".format(text))

class UnionFind():
    def __init__(self, N):
        self._parent = [n for n in range(0, N)]
        self._size = [1] * N

    def find_root(self, x):
        if self._parent[x] == x: return x
        self._parent[x] = self.find_root(self._parent[x])
        return self._parent[x]

    def unite(self, x, y):
        gx = self.find_root(x)
        gy = self.find_root(y)
        if gx == gy: return

        if self._size[gx] < self._size[gy]:
            self._parent[gx] = gy
            self._size[gy] += self._size[gx]
        else:
            self._parent[gy] = gx
            self._size[gx] += self._size[gy]

    def get_size(self, x):
        return self._size[self.find_root(x)]

    def is_same_group(self, x, y):
        return self.find_root(x) == self.find_root(y)

    def calc_group_num(self):
        N = len(self._parent)
        ans = 0
        for i in range(N):
            if self.find_root(i) == i:
                ans += 1
        return ans



INF=10**20
def main():
    N,M=mi()
    P = []
    for p in mi():
        P.append(p-1)

    uni = UnionFind(N)
    for i in range(M):
        x,y = mi()
        uni.unite(x-1,y-1)
    
    ans = 0

    for i in range(N):
        if uni.find_root(i) == uni.find_root(P[i]):
            ans += 1

    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 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):
    from collections import defaultdict
    ret = defaultdict(list)
    for i in range(self.n):
      ret[self.find(i)].append(i)
    return ret

  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()))

uf = UnionFind(N)

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

D = uf.all_group_members()

ans = 0

for L in D.values():
  check = set(L)
  for i in L:
    if P[i]-1 in check:
      ans += 1 

print(ans)