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 sys
from collections import deque

sys.setrecursionlimit(10**5+10)

input = lambda: sys.stdin.readline().rstrip()

N, M = map(int, input().split())
p = list(map(int, input().split()))
p_inv = [0]*(N+1)
for i in range(1, N+1):
    p_inv[p[i-1]] = i

graph = [[] for _ in range(N+1)]
for i in range(M):
    x, y = map(int, input().split())
    graph[x].append(y)
    graph[y].append(x)

stack = deque()
is_checked = [0] * (N+1)
links = [[] for _ in range(N+1)]
for i in range(1, N+1):
    stack.append(i)
    while stack:
        node = stack.pop()
        if is_checked[node]:
            continue

        links[i].append(node)
        for next in graph[node]:
            stack.append(next)

        is_checked[node] = 1

ans = 0
for l in links:
    check = set()
    for num in l:
        check.add(p_inv[num])
    l = set(l)
    ans += len(l & check)

print(ans)

Solution (Python):
from collections import deque
N,M=map(int,input().split())
p=list(map(int,input().split()))
fromto=[]
tree=[[] for _ in range(N)]
for i in range(N):
    fromto.append([i,p[i]-1])
cnt=0
for i in range(M):
    x,y=map(int,input().split())
    tree[x-1].append(y-1)
    tree[y-1].append(x-1)
col=[-1]*N
for i in range(N):
    if col[i]==-1:
        d = deque()
        d.append(i)
        while len(d)>0:
            v=d.popleft()
            col[v]=i
            for j in tree[v]:
                if col[j]==-1:
                    d.append(j)
            
            

for i in range(N):
    x=fromto[i][0]
    y=fromto[i][1]
    if col[x]==col[y]:
        cnt=cnt+1
print(cnt)

Solution (Python):
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):
        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]:
                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 all_group_members(self):
        return_list = [list() for i in range(n)]
        for i in range(n):
          return_list[self.find(i)].append(i)
        return return_list
      
      
n,m = map(int, input().split())
p = [x-1 for x in list(map(int, input().split()))]
key = dict()
for k,v in enumerate(p):
  key[v] = k
Union = UnionFind(n)
xy = [list(map(int, input().split())) for i in range(m)]
for x,y in xy:
  Union.union(x-1,y-1)
a = Union.all_group_members()
ans = 0
for i in a:
  x = set()
  for j in i:
    x.add(key[j])
  y = set(i)
  ans += len(x & y)
print(ans)

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

class UnionFind:
    def __init__(self, n):
        self.par = list(range(n))
        self.siz = [1] * n
    
    def root(self, x):
        if self.par[x] == x: return x
        self.par[x] = self.root(self.par[x])
        return self.par[x]

    def size(self, x):
        self.siz[self.root(x)]

    def unite(self, x, y):
        rx, ry = self.root(x), self.root(y)
        if rx != ry:
            if self.siz[rx] < self.siz[ry]: 
                rx, ry = ry, rx
            self.par[ry] = rx
            self.siz[rx] += self.siz[ry]
    
    def same(self, x, y):
        return self.root(x) == self.root(y)

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, val in enumerate(p):
    if uf.same(i, val-1):
        ans += 1
print(ans)

Solution (Python):

import sys
try:
    from typing import List
except ImportError:
    pass


def solve(N: int, M: int, p: "List[int]", x: "List[int]", y: "List[int]"):
    pars = list(range(N))

    def getpar(n: int):
        if pars[n] == n:
            return n
        pars[n] = getpar(pars[n])
        return pars[n]

    def union(a: int, b: int):
        pars[getpar(a)] = getpar(b)

    for xi, yi in zip(x, y):
        union(xi - 1, yi - 1)
    print(sum(
        1
        for i in range(N)
        if getpar(p[i] - 1) == getpar(i)
    ))


def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  
    M = int(next(tokens))  
    p = [int(next(tokens)) for _ in range(N)]  
    x = [int()] * (M)  
    y = [int()] * (M)  
    for i in range(M):
        x[i] = int(next(tokens))
        y[i] = int(next(tokens))
    solve(N, M, p, x, y)


if __name__ == '__main__':
    main()

Solution (Python):
nim, M = map(int, input().split())
ps = list(map(int, input().split()))
G = list(range(nim))
def getparent(n):
  if G[n] == n:
    return n
  G[n] = getparent(G[n])
  return G[n]
for i in range(M):
  x, y = map(int, input().split())
  x, y = x-1, y-1
  x = getparent(x)
  y = getparent(y)
  G[x] = y
Ss = [set() for i in range(nim)]
for i in range(nim):
  j = getparent(i)
  Ss[j].add(ps[i])
r = 0
for i in range(nim):
  if i+1 in Ss[G[i]]:
    r += 1
print(r)

Solution (Python):
def main():
    import sys
    input = sys.stdin.readline
    sys.setrecursionlimit(10**7)
    from collections import Counter, deque
    
    from itertools import combinations, permutations, accumulate, groupby, product
    from bisect import bisect_left,bisect_right
    from heapq import heapify, heappop, heappush
    from math import floor, ceil
    

    
    

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

    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)
    
    par = [-1]*n

    for x, y in xy:
        if same(x-1, y-1) == False:
            unite(x-1, y-1)
    res = 0
    for i in range(n):
        if i == p[i]-1:
            res += 1
        else:
            if same(i, p[i]-1):
                res += 1
    print(res)

if __name__ == '__main__':
    main()

Solution (Python):
def LI(): return [int(i) for i in input().split()]
def LI_(): return [int(i)-1 for i in input().split()]
def LIR_(n): return [LI_() for i in range(n)]
def D():
    n, m = LI()
    p = LI_()
    xy = LIR_(m)
    size = [1 for _ in range(n)]
    height = [1 for _ in range(n)]
    par = [i 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(x, y):
        s1 = find(x)
        s2 = find(y)
        if s1 != s2:
            if height[s1] < height[s2]:
                par[s1] = s2
                size[s2] += size[s1]
                size[s1] = 0
            else:
                par[s2] = s1
                size[s1] += size[s2]
                size[s2] = 0
                if height[s1] == height[s2]:
                    height[s1] += 1
 
    for x,y in xy:
        union(x, y)
    ans = 0
    for i in range(n):
        if find(p[i]) == find(i):
            ans += 1
    
    print(ans)
D()

Solution (Python):

import sys

sys.setrecursionlimit(10 ** 6)


class UnionFind:
    def __init__(self, size):
        self.size = size
        self.parents = [i for i in range(size)]
        self.ranks = [0 for i in range(size)]

    def ancestor(self, i):
        if self.parents[i] == i:
            return i
        else:
            self.parents[i] = self.ancestor(self.parents[i])
            return self.parents[i]

    def union(self, i, j):
        ip = self.ancestor(i)
        jp = self.ancestor(j)
        if ip == jp:
            return False
        else:
            if self.ranks[ip] > self.ranks[jp]:
                self.parents[jp] = ip
            else:
                self.parents[ip] = jp
                if self.ranks[ip] == self.ranks[jp]:
                    self.ranks[ip] += 1

    def same(self, i, j):
        return self.ancestor(i) == self.ancestor(j)

    def __str__(self):
        parentDict = { }
        for i in range(self.size):
            a = self.ancestor(i)
            if a not in parentDict:
                parentDict[a] = [i]
            else:
                parentDict[a].append(i)
        result = "===UnionFind description===\nSize:" + str(self.size) + "\nGroupCount:" + str(
            len(parentDict)) + "\n\nGroups:\n"
        for k in parentDict.keys():
            elements = ""
            for elem in parentDict[k]:
                elements += " " + str(elem) + ","
            result += "Group-"+str(k)+"(Count:"+str(len(parentDict[k]))+"):["+elements+"]\n"
        return result


def solve(N: int, M: int, p: "List[int]", x: "List[int]", y: "List[int]"):
    U = UnionFind(N)
    for i in range(M):
        U.union(x[i] - 1, y[i] - 1)
    sum = 0
    for i in range(N):
        if p[i] == i + 1 or U.same(p[i] - 1, i):
            sum += 1
    print(sum)
    return



def main():
    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word

    tokens = iterate_tokens()
    N = int(next(tokens))  
    M = int(next(tokens))  
    p = [int(next(tokens)) for _ in range(N)]  
    x = [int()] * (M)  
    y = [int()] * (M)  
    for i in range(M):
        x[i] = int(next(tokens))
        y[i] = int(next(tokens))
    solve(N, M, p, x, y)


if __name__ == '__main__':
    main()

Solution (Python):
N, M = map(int,input().split())
P = 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):
        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]

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

ans = 0

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

Solution (Python):
import numpy as np
from scipy.sparse.csgraph import connected_components
from scipy.sparse import csr_matrix

int1 = lambda x: int(x) - 1

N, M = map(int, input().split())
P = tuple(map(int1, input().split()))

edge = np.array([tuple(map(int1, input().split())) for _ in range(M)]).T
matr = csr_matrix((np.ones(M, dtype="int64"), edge), (N, N))

C, labels = connected_components(matr)
lst = [[set(), set()] for _ in range(C)]
for i, x in enumerate(labels):
    lst[x][0].add(i)
    lst[x][1].add(P[i])

for c in range(C):
    lst[c] = lst[c][0] & lst[c][1]
print(sum(len(s) for s in lst))

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


U=[i for i in range(N+1)] 


def root(x):
    global U
    if x==U[x]:
        return x
    else:
        U[x]=root(U[x])  
        return U[x]


def unite(x,y):
    global U
    if root(x)!=root(y):
        U[root(x)]=root(y)


def same(x,y):
    global U
    if root(x)==root(y):
        return 1
    else:
        return 0

for j in range(M):
    X,Y=map(int,input().split())
    unite(X,Y)

ans=0
for k in range(1,N+1):
    ans+=same(k,P[k])

print(ans)

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


par = [-1] * (n + 1)


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


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


def is_same(x, y):
    return root(x) == root(y)


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




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

cnt = 0
for i in range(n):
    if is_same(P[i], i + 1):
        cnt += 1
print(cnt)

Solution (Python):
import sys
input = sys.stdin.readline
n,m = [int(i) for i in input().split()]
p = [int(i) for i in input().split()]
p = tuple(p)
chk = [[set(),set()] for i in range(n)]
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)
  
par = [-1]*n
ans = 0
for i in range(m):
  x,y = [int(i) for i in input().split()]
  unite(x-1,y-1)

for i,pi in enumerate(p):
  if same(i,pi-1):
    ans += 1
    
print(ans)

Solution (Python):
import sys
input = sys.stdin.readline
n,m = [int(i) for i in input().split()]
p = [int(i) for i in input().split()]
p = tuple(p)
chk = [[set(),set()] for i in range(n)]
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
      
par = [-1]*n
ans = 0
for i in range(m):
  x,y = [int(i) for i in input().split()]
  unite(x-1,y-1)

for i in range(n):
  m = find(i)
  chk[m][0].add(p[i])
  chk[m][1].add(i+1)

for i in range(n):
  ans += len(chk[i][0] & chk[i][1])
    
print(ans)

Solution (Python):
import sys
IS = lambda: sys.stdin.readline().rstrip()
II = lambda: int(IS())
MII = lambda: list(map(int, IS().split()))
_DEC = lambda x: x-1
MIIZ = lambda: list(map(_DEC, MII()))

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

def main():
    n, m = MII()
    pp = MIIZ()
    uf = UnionFind(n)
    for i in range(m):
        x, y = MIIZ()
        uf.union(x, y)
    cnt = 0
    for i, p in enumerate(pp):
        if uf.find(i) == uf.find(p): cnt += 1
    print(cnt)

if __name__ == '__main__':
    main()

Solution (Python):


class UnionFind():
    def __init__(self, n):
        self.par = [i for i in range(n + 1)]
        self.size = [1 for i in range(n + 1)]

    def find(self, x):
        if x == self.par[x]:
            return self.par[x]
        self.par[x] = self.find(self.par[x])
        return self.par[x]

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

    def unite(self, x, y):
        if self.same(x, y):
            return
        xr = self.find(x)
        yr = self.find(y)
        if self.size[xr] > self.size[yr]:
            xr, yr = yr, xr
        self.size[yr] = self.size[xr] + self.size[yr]
        self.par[xr] = yr


def submit():
    n, m = map(int, input().split())
    plist = list(map(int, input().split()))
    
    uf = UnionFind(n)
    for _ in range(m):
        x, y = map(int, input().split())
        uf.unite(x, y)

    groups = {}
    for i in range(1, n + 1):
        r = uf.find(i)
        if r not in groups.keys():
            groups[r] = {i}
        else:
            groups[r].add(i)

    ans = 0
    for group in groups.values():
        for g in group:
            if plist[g - 1] in group:
                ans += 1
    print(ans)


submit()

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

def get_par(x):
  if x == par_list[x]:
    return x
  else:
    par_list[x] = get_par(par_list[x])
    return par_list[x]

def merge(x,y):
  par_x = get_par(x)
  par_y = get_par(y)
  if par_x != par_y:
    par_list[par_y] = par_x

def is_same(x,y):
  return get_par(x) == get_par(y)

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


par_list=list(range(N+1))
for i in range(M):
  x,y=map(int,input().split())
  merge(x,y)
  
for i in range(1,N+1):
  par_list[i]=get_par(i)

  
answer=0
for i in range(N):
  if get_par(i+1)==get_par(plist[i]):
    answer+=1
    
print(answer)

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

def get_par(x):
  if x == par_list[x]:
    return x
  else:
    par_list[x] = get_par(par_list[x])
    return par_list[x]

def merge(x,y):
  par_x = get_par(x)
  par_y = get_par(y)
  if par_x != par_y:
    par_list[par_y] = par_x

def is_same(x,y):
  return get_par(x) == get_par(y)

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


par_list=list(range(N+1))
for i in range(M):
  x,y=map(int,input().split())
  merge(x,y)


index_dic={}
comp_list=[]
for i in range(1,N+1):
  par=get_par(par_list[i])
  comp_list.append(par)
  if par in index_dic:
    index_dic[par].append(i)
  else:
    index_dic[par]=[i]



answer=0
for par,vlist in index_dic.items():
  v2set=set()
  for v in vlist:
    v2set.add(plist[v-1])
      
  
  
  for v in vlist:
    if v in v2set:
      answer+=1
      
print(answer)

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

class UnionFind:
    __slots__ = ["data"]
    
    def __init__(self, n=0):
        self.data = [-1]*(n+1)
    
    def root(self, x):
        if self.data[x] < 0:
            return x
        self.data[x] = self.root(self.data[x])
        return self.data[x]
    
    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x != y:
            if self.data[x] < self.data[y]:
                self.data[x] += self.data[y]
                self.data[y] = x
            else:
                self.data[y] += self.data[x]
                self.data[x] = y
    
    def same(self, x, y):
        return self.root(x) == self.root(y)
    
    def size(self, x):
        return -self.data[self.root(x)]


def main():
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    uf = UnionFind(n)
    for _ in range(m):
        x, y = map(int, input().split())
        uf.unite(x, y)
    cnt = 0
    for i in range(1, n+1):
        if uf.same(i, p[i-1]):
            cnt += 1
    print(cnt)

if __name__ == "__main__":
    main()

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

def main():
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    cnt = 0
    
    def root(x):
        if parent[x] == x:
            return x
        parent[x] = root(parent[x])
        return parent[x]
    
    def unite(x, y):
        x = root(x)
        y = root(y)
        if x != y:
            if rank[x] > rank[y]:
                parent[y] = x
            elif rank[x] < rank[y]:
                parent[x] = y
            else:
                parent[y] = x
                rank[x] += 1

    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i, pi in enumerate(p, 1):
        if root(i) == root(pi):
            cnt += 1
    print(cnt)

if __name__ == "__main__":
    main()

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

def main():
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    cnt = 0
    
    def root(x):
        if parent[x] == x:
            return x
        parent[x] = root(parent[x])
        return parent[x]
    
    def unite(x, y):
        x = root(x)
        y = root(y)
        if x != y:
            if rank[x] < rank[y]:
                parent[x] = y
            elif rank[x] > rank[y]:
                parent[y] = x
            else:
                parent[y] = x
                rank[x] += 1

    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i, pi in enumerate(p, 1):
        if root(i) == root(pi):
            cnt += 1
    print(cnt)

if __name__ == "__main__":
    main()

Solution (Python):
import sys
input = sys.stdin.buffer.readline
def main():
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    cnt = 0
    
    def root(x):
        if parent[x] == x:
            return x
        parent[x] = root(parent[x])
        return parent[x]
    
    def unite(x, y):
        x = root(x)
        y = root(y)
        if x != y:
            if rank[x] < rank[y]:
                parent[x] = y
            elif rank[x] > rank[y]:
                parent[y] = x
            else:
                parent[y] = x
                rank[x] += 1

    for _ in range(m):
        x, y = map(int, input().split())
        x = root(x)
        y = root(y)
        if x != y:
            parent[y] = x
    for i, pi in enumerate(p, 1):
        if root(i) == root(pi):
            cnt += 1
    print(cnt)

if __name__ == "__main__":
    main()

Solution (Python):
def main():
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    cnt = 0
    
    def root(x):
        if parent[x] == x:
            return x
        parent[x] = root(parent[x])
        return parent[x]
    
    def unite(x, y):
        x = root(x)
        y = root(y)
        if x != y:
            if rank[x] < rank[y]:
                parent[x] = y
            elif rank[x] > rank[y]:
                parent[y] = x
            else:
                parent[y] = x
                rank[x] += 1

    for _ in range(m):
        x, y = map(int, input().split())
        x = root(x)
        y = root(y)
        if x != y:
            parent[y] = x
    for i, pi in enumerate(p, 1):
        if root(i) == root(pi):
            cnt += 1
    print(cnt)

if __name__ == "__main__":
    main()

Solution (Python):
def main():
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    cnt = 0
    
    def root(x):
        if parent[x] == x:
            return x
        parent[x] = root(parent[x])
        return parent[x]
    
    def unite(x, y):
        x = root(x)
        y = root(y)
        if x != y:
            if rank[x] < rank[y]:
                parent[x] = y
            elif rank[x] > rank[y]:
                parent[y] = x
            else:
                parent[y] = x
                rank[x] += 1

    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i, pi in enumerate(p, 1):
        if root(i) == root(pi):
            cnt += 1
    print(cnt)

if __name__ == "__main__":
    main()

Solution (Python):
def main():
    cnt = 0
    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i, pi in enumerate(p, 1):
        if root(i) == root(pi):
            cnt += 1
    print(cnt)
        
def root(x):
    if parent[x] == x:
        return x
    parent[x] = root(parent[x])
    return parent[x]

def unite(x, y):
    x = root(x)
    y = root(y)
    if x != y:
        if rank[x] < rank[y]:
            parent[x] = y
        elif rank[x] > rank[y]:
            parent[y] = x
        else:
            parent[y] = x
            rank[x] += 1

if __name__ == "__main__":
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    main()

Solution (Python):
def main():
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    global parent, rank
    parent = list(range(n+1))
    rank = [0]*(n+1)
    cnt = 0
    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i, pi in enumerate(p, 1):
        if same(i, pi):
            cnt += 1
    print(cnt)
        
def root(x):
    if parent[x] == x:
        return x
    parent[x] = root(parent[x])
    return parent[x]

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

def unite(x, y):
    x = root(x)
    y = root(y)
    if x != y:
        if rank[x] < rank[y]:
            parent[x] = y
        elif rank[x] > rank[y]:
            parent[y] = x
        else:
            parent[y] = x
            rank[x] += 1

if __name__ == "__main__":
    main()

Solution (Python):
def main():
    cnt = 0
    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i, pi in enumerate(p, 1):
        if same(i, pi):
            cnt += 1
    print(cnt)
        
def root(x):
    if parent[x] == x:
        return x
    parent[x] = root(parent[x])
    return parent[x]

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

def unite(x, y):
    x = root(x)
    y = root(y)
    if x != y:
        if rank[x] < rank[y]:
            parent[x] = y
        elif rank[x] > rank[y]:
            parent[y] = x
        else:
            parent[y] = x
            rank[x] += 1

if __name__ == "__main__":
    n, m = map(int, input().split())
    p = list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    main()

Solution (Python):
def main():
    cnt = 0
    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i in range(1, n+1):
        if same(i, p[i]):
            cnt += 1
    print(cnt)
        
def root(x):
    if parent[x] == x:
        return x
    parent[x] = root(parent[x])
    return parent[x]

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

def unite(x, y):
    x = root(x)
    y = root(y)
    if x != y:
        if rank[x] < rank[y]:
            parent[x] = y
        elif rank[x] > rank[y]:
            parent[y] = x
        else:
            parent[y] = x
            rank[x] += 1

if __name__ == "__main__":
    n, m = map(int, input().split())
    p = [0] + list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    main()

Solution (Python):
def main():
    cnt = 0
    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i in range(1, n+1):
        if same(i, p[i]):
            cnt += 1
    print(cnt)
        
def root(x):
    if parent[x] == x:
        return x
    parent[x] = root(parent[x])
    return parent[x]

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

def unite(x, y):
    x = root(x)
    y = root(y)
    if x != y:
        if rank[x] < rank[y]:
            parent[x] = y
        elif rank[x] > rank[y]:
            parent[y] = x
        else:
            parent[y] = x
            rank[x] += 1

if __name__ == "__main__":
    n, m = map(int, input().split())
    p = [0] + list(map(int, input().split()))
    parent = list(range(n+1))
    rank = [0]*(n+1)
    main()

Solution (Python):
def main():
    cnt = 0
    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i in range(1, n+1):
        if same(i, p[i]):
            cnt += 1
    print(cnt)
        
def root(x):
    if par[x] == x:
        return x
    par[x] = root(par[x])
    return par[x]

def same(x, y):
    rx = root(x)
    ry = root(y)
    return rx == ry

def unite(x, y):
    x = root(x)
    y = root(y)
    if x != y:
        par[x] = y

if __name__ == "__main__":
    n, m = map(int, input().split())
    p = [0] + list(map(int, input().split()))
    par = list(range(n+1))
    main()

Solution (Python):
def main():
    cnt = 0
    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i in range(1, n+1):
        if same(i, p[i]):
            cnt += 1
    print(cnt)
        
def root(x):
    if par[x] == x:
        return x
    par[x] = root(par[x])
    return par[x]

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

def unite(x, y):
    x = root(x)
    if x != root(y):
        par[x] = y

if __name__ == "__main__":
    n, m = map(int, input().split())
    p = [0] + list(map(int, input().split()))
    par = list(range(n+1))
    main()

Solution (Python):
def main():
    cnt = 0
    for _ in range(m):
        x, y = map(int, input().split())
        unite(x, y)
    for i in range(1, n+1):
        if same(i, p[i]):
            cnt += 1
    print(cnt)
        
def root(x):
    if par[x] == x:
        return x
    par[x] = root(par[x])
    return par[x]

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

def unite(x, y):
    x = root(x)
    y = root(y)
    if x != y:
        par[x] = y

if __name__ == "__main__":
    n, m = map(int, input().split())
    p = [0] + list(map(int, input().split()))
    par = list(range(n+1))
    main()