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,math,collections,itertools
input = sys.stdin.readline

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

memo = [-1]*(N+1)
q = collections.deque([])
novisit = set(range(1,N+1))
tmp = 0
while novisit:
    q.append(novisit.pop())
    tmp+=1
    while q:
        now = q.pop()
        memo[now]=tmp
        for bri in bridge[now]:
            if bri in novisit:
                q.append(bri)
                novisit.discard(bri)

cnt = 0
for i in range(N):
    if i+1 == P[i]:
        cnt += 1
    elif i+1 != P[i] and memo[P[i]] == memo[i+1] :
        cnt += 1
print(cnt)

Solution (Python):
n,m=map(int,input().split())
*p,=map(int,input().split())
p=[z-1 for z in p]
es=[[] for _ in range(n)]
for _ in range(m):
    x,y=map(int,input().split())
    es[x-1].append(y-1)
    es[y-1].append(x-1)

group=[-1]*n
last=-1
for i in range(n):
    if group[i]==-1:
        last+=1
        group[i]=last
        stack=[i]
        while stack:
            j=stack.pop()
            for e in es[j]:
                if group[e]==-1:
                    stack.append(e)
                    group[e]=last
groupset=set(group)
group1=[[] for g in groupset]
group2=[[] for g in groupset]

for i in range(n):
    group1[group[i]].append(i)
    group2[group[i]].append(p[i])

ans=0
for g in groupset:
    ans+=len(set(group1[g])&set(group2[g]))
print(ans)

Solution (Python):
import sys
import queue

input_methods=['clipboard','file','key']
using_method=0
input_method=input_methods[using_method]

tin=lambda : map(int, input().split())
lin=lambda : list(tin())
mod=1000000007



def main():
	
	n, m = tin()
	
	al = [-1]+lin()
	bb=[[] for _ in range(n+1)]
	for _ in range(m):
		a, b = tin()
		bb[a].append(b)
		bb[b].append(a)
		
	ll=[]
	is_open = [0] *(n+1)
	for i in range(n+1):
		q=queue.Queue()
		q.put(i)
		t=[]
		while not q.empty():
			pp=q.get()
			if is_open[pp] != 0:
				continue
			is_open[pp]=1
			t.append(pp)
			for v in bb[pp]:
				q.put(v)
		ll.append(t)
	
	ret = 0
	
	for t in ll:
		st=set(t)
		for v in t:
			if al[v] in st:
				ret += 1
	print(ret)
				
		
		
	
	
	
	
	

isTest=False

def pa(v):
	if isTest:
		print(v)
		
def input_clipboard():
	import clipboard
	input_text=clipboard.get()
	input_l=input_text.splitlines()
	for l in input_l:
		yield l

if __name__ == "__main__":
	if sys.platform =='ios':
		if input_method==input_methods[0]:
			ic=input_clipboard()
			input = lambda : ic.__next__()
		elif input_method==input_methods[1]:
			sys.stdin=open('inputFile.txt')
		else:
			pass
		isTest=True
	else:
		pass
		
			
	ret = main()
	if ret is not None:
		print(ret)

Solution (Python):
from collections import deque

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

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

root = [[] for i in range(n)]
for _ in range(m):
    a, b = (int(x) for x in input().split())
    root[b-1].append(a-1)
    root[a-1].append(b-1)

check = [-1]*n

for j in range(n):
    if check[j] != -1:
        continue
    stack=deque([j])
    check[j] = j
    while len(stack)>0:
        v = stack.popleft()
        for i in root[v]:
            if check[i] == -1:
                check[i]=j
                stack.append(i)

ans = 0
for key, value in enumerate(p):
    if check[key] == check[value-1]:
        ans += 1
print(ans)

Solution (Python):
ma = lambda :map(int,input().split())
lma = lambda :list(map(int,input().split()))
ni = lambda:int(input())
yn = lambda fl:print("Yes") if fl else print("No")
import collections
import math
import itertools
import heapq as hq

class unionfind():
    def __init__(self,n):
        self.par = list(range(n))
        self.size = [1]*n
        self.rank = [0]*n

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

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

    def unite(self,x,y):
        x = self.root(x)
        y = self.root(y)
        if x==y:return
        else:
            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.root(x)
        return self.size[x]
n,m = ma()
P = lma()
uf = unionfind(n+1)
for i in range(m):
    x,y = ma()
    uf.unite(x,y)
ans = 0
for i in range(n):
    if uf.same(i+1,P[i]):
        ans+=1
print(ans)

Solution (Python):
class UnionFind:
    def __init__(self, num):
        self.parent = [i for i in range(num + 1)]

    def find(self, node):
        if self.parent[node] == node:
            return node

        self.parent[node] = self.find(self.parent[node])
        return self.parent[node]

    def union(self, node1, node2):
        node1 = self.find(node1)
        node2 = self.find(node2)

        if node1 == node2:
            return

        if self.parent[node1] > self.parent[node2]:
            node1, node2 = node2, node1

        self.parent[node2] = node1
        return

    def same(self, node1, node2):
        return self.find(node1) == self.find(node2)


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())
    x -= 1
    y -= 1
    uf.union(p[x], p[y])

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

print(ans)

Solution (Python):
n,m=map(int, input().split())
p=list(map(lambda x: int(x)-1, 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 size(self, x):
        return -self.parents[self.find(x)]

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

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

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

    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 _ in range(m):
    x,y=map(lambda x: int(x)-1, input().split())
    uf.union(x,y)

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

Solution (Python):
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.root = [-1]*(n+1)
        self.rnk = [0]*(n+1)
    def find(self, x):
        if(self.root[x] < 0):
            return x
        else:
            self.root[x] = self.find(self.root[x])
            return self.root[x]
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if(x == y):return 
        elif(self.rnk[x] > self.rnk[y]):
            self.root[x] += self.root[y]
            self.root[y] = x
        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            if(self.rnk[x] == self.rnk[y]):
                self.rnk[y] += 1
    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)
for _ in range(m):
  a,b=map(int,input().split())
  uf.unite(a,b)
cnt=0
for i,j in enumerate(p):
  if uf.same(i,j):cnt+=1
print(cnt-1)

Solution (Python):
import sys
import math
import collections
import bisect
import copy
import itertools



sys.setrecursionlimit(10 ** 7)
INF = 10 ** 16
MOD = 10 ** 9 + 7


ni = lambda: int(sys.stdin.readline().rstrip())
ns = lambda: map(int, sys.stdin.readline().rstrip().split())
na = lambda: list(map(int, sys.stdin.readline().rstrip().split()))
na1 = lambda: list(map(lambda x: int(x) - 1, sys.stdin.readline().rstrip().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 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 = ns()
    p = na1()

    uf = UnionFind(n)

    for _ in range(m):
        x, y = ns()
        uf.union(x - 1, y - 1)

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

    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
import sys
import math
import collections
import bisect
import copy
import itertools



sys.setrecursionlimit(10 ** 7)
INF = 10 ** 16
MOD = 10 ** 9 + 7


ni = lambda: int(sys.stdin.readline().rstrip())
ns = lambda: map(int, sys.stdin.readline().rstrip().split())
na = lambda: list(map(int, sys.stdin.readline().rstrip().split()))
na1 = lambda: list(map(lambda x: int(x) - 1, sys.stdin.readline().rstrip().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 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 = ns()
    p = na1()

    uf = UnionFind(n)

    for _ in range(m):
        x, y = ns()
        uf.union(x - 1, y - 1)

    ans = 0
    for i, pi in enumerate(p):
        if uf.same(i, pi):
            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 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 [set(self.members(r)) for r in self.roots()]

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

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

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

if __name__ == '__main__':
    main()

Solution (Python):
'''
自宅用PCでの解答
'''
import math

import itertools
import queue
import bisect
from collections import deque,defaultdict
import heapq as hpq
from sys import stdin,setrecursionlimit


ipt = stdin.readline
setrecursionlimit(10**7)
mod = 10**9+7
dir = [(-1,0),(0,-1),(1,0),(0,1)]
alp = "abcdefghijklmnopqrstuvwxyz"


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 set([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 [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 = map(int,ipt().split())
    p = [int(i)-1 for i in ipt().split()]
    uf = UnionFind(n)
    for i in range(m):
        x,y = map(int,ipt().split())
        uf.union(x-1,y-1)

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

    print(ans)

    return None

if __name__ == '__main__':
    main()

Solution (Python):
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]
def unite(x, y):
    p = find(x)
    q = find(y)
    if p == q:
        return None
    if p > q:
        p, q = q, p
    par[p] += par[q]
    par[q] = p
def same(x, y):
    return find(x) == find(y)
def size(x):
    return -par[find(x)]
n, m = map(int, input().split())
par = [-1 for i in range(n)]
p = list(map(int, input().split()))
for i in range(m):
    x, y = map(int, input().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):
import sys

sys.setrecursionlimit(6500)

def find(n):
    if d[n]<0:
        return n
    else:
        d[n]=find(d[n])
        return d[n]

def union(a,b):
    a=find(a)
    b=find(b)
    if a==b:return False
    if d[a]<=d[b]:
        d[a]+=d[b]
        d[b]=a
    else:
        d[b]+=d[a]
        d[a]=b
    return True

def members(n):
    p=find(n)
    ans=[]
    for i in range(N):
        if find(i)==p:
            ans.append(i)
    return ans

def same(a,b):
    if find(a)==find(b):return True
    else:return False

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

d=[-1]*N

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

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

Solution (Python):
n,m=list(map(int,input().split()))
a=list(map(int,input().split()))
s=[[] for i in range(n)]
for i in range(m):
  inp=list(map(int,input().split()))
  s[inp[0]-1].append(inp[1]-1)
  s[inp[1]-1].append(inp[0]-1)
c=0
d=[0 for i in range(n)]
for i in range(n):
  if d[i]:
    continue
  c+=1
  d[i]=c
  st=s[i]
  while st:
    ns=[]
    for j in st:
      if d[j]:
        continue
      d[j]=c
      ns+=s[j]
    st=ns
c=0
for i in range(n):
  if d[i]==d[a[i]-1]:
    c+=1
print(c)

Solution (Python):
import sys

sys.setrecursionlimit(6500)

def find(n):
    if d[n]<0:
        return n
    else:
        d[n]=find(d[n])
        return d[n]

def union(a,b):
    a=find(a)
    b=find(b)
    if a==b:return False
    if d[a]<=d[b]:
        d[a]+=d[b]
        d[b]=a
    else:
        d[b]+=d[a]
        d[a]=b
    return True

def members(n):
    p=find(n)
    ans=[]
    for i in range(N):
        if find(i)==p:
            ans.append(i)
    return ans

def same(a,b):
    if find(a)==find(b):return True
    else:return False

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

d=[-1]*N

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

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

Solution (Python):
import sys
from collections import deque
readline = sys.stdin.readline
n, m = map(int, readline().split())
P = list(map(lambda x:int(x)-1, readline().split()))
G = [set() for _ in range(n)]
for i in range(m):
    x, y = map(lambda x:int(x)-1, readline().split())
    G[x].add(y)
    G[y].add(x)

D = {}
cnt = 0
V = [-1]*n
for i in range(n):
    if V[i]!=-1: continue
    V[i] = cnt
    que = deque([i])
    D[cnt] = set([P[i]])
    while que:
        nw = que.popleft()
        for nx in G[nw]:
            if V[nx] != -1: continue
            D[cnt].add(P[nx])
            V[nx] = cnt
            que.append(nx)
    cnt += 1
print(sum([int(i in D[V[i]]) for i in range(n)]))

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

class UnionFind(object):
    def __init__(self, n):
        self._par = list(range(n))
        self.size = [1]*n

    def root(self, v):
        if self._par[v] == v:
            return v
        self._par[v] = self.root(self._par[v])
        return self._par[v]
    
    def unite(self, u, v):
        u, v = self.root(u), self.root(v)
        if u==v:
            return False
        if self.size[u] > self.size[v]:
            u, v = v, u
        self.size[v] += self.size[u]
        self._par[u] = v

    def is_connected(self, u, v):
        return self.root(u)==self.root(v)

n, m = map(int, readline().split())
P = list(map(lambda x:int(x)-1, readline().split()))
uf = UnionFind(n)
for _ in range(m):
    x, y = map(lambda x:int(x)-1, readline().split())
    uf.unite(x,y)

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

Solution (Python):
def find(x):
    '''
    xの根を求める
    '''
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]


def union(x, y):
    '''
    xとyの属する集合の併合
    '''
    x = find(x)
    y = find(y)
    
    if x == y:
        return

    if par[x] > par[y]:
        x, y = y, x

    par[x] += par[y]
    par[y] = x


def size(x):
    '''
    xが属する集合の個数
    '''
    return -par[find(x)]


def same(x, y):
    '''
    xとyが同じ集合に属するかの判定
    '''
    return find(x) == find(y)


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

par = [-1] * n

pos = [-1] * n
for i in range(n):
    pos[p[i]-1] = i

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

res = 0
for i in range(n):
    if same(i, pos[i]):
        res += 1

print(res)

Solution (Python):
import sys
from collections import deque

input = sys.stdin.readline

def bfs(N, G, p):
    
    c_comp_p_list = []
    c_comp_i_list = []
    visited = [False] * N
    for i in range(N):
        if visited[i]:
            continue
        visited[i] = True
        c_comp_p_list.append([p[i]])
        c_comp_i_list.append(set([i + 1]))
        cc_p_add = c_comp_p_list[-1].append
        cc_i_add = c_comp_i_list[-1].add

        queue = deque(G[i])
        while queue:
            u = queue.popleft()
            if visited[u]:
                continue
            visited[u] = True
            cc_p_add(p[u])
            cc_i_add(u + 1)

            for v in G[u]:
                if visited[v]:
                    continue
                queue.append(v)

    res = 0
    for c_comp_p, c_comp_i in zip(c_comp_p_list, c_comp_i_list):
        for pp in c_comp_p:
            if pp in c_comp_i:
                res += 1
    return res


def main():
    N, M = map(int, input().split())
    p = tuple(map(int, input().split()))
    G = [[] for _ in range(N)]
    for _ in range(M):
        x, y = map(int, input().split())
        x -= 1
        y -= 1
        G[x].append(y)
        G[y].append(x)
    
    ans = bfs(N, G, p)
    print(ans)


if __name__ == "__main__":
    main()

Solution (Python):
from collections import deque

n, m = map(int, input().split())
plst = list(map(int, input().split()))
edges = [[] for _ in range(n)]
for _ in range(m):
    x, y = map(int, input().split())
    x -= 1
    y -= 1
    edges[x].append(y)
    edges[y].append(x)
    
check = [False for _ in range(n)]
uni = [0 for _ in range(n)]
pos = 0
queue = deque()
for i in range(n):
    if check[i]:
        continue
    pos += 1
    queue.append(i)
    check[i] = True
    while queue:
        now = queue.popleft()
        uni[now] += pos
        uni[plst[now] - 1] -= pos
        for aft in edges[now]:
            if check[aft]:
                continue
            check[aft] = True
            queue.append(aft)
print(uni.count(0))

Solution (Python):
n,m=map(int,input().split())
P=[int(i) for i in input().split()]

uf=[i for i in range(n+1)]
def ufuf(x):
    while x!=uf[x]:
        x=uf[x]
    return x

for i in range(m):
    x,y=map(int,input().split())
    if ufuf(x)<ufuf(y):
        uf[ufuf(y)]=ufuf(x)
    else:
        uf[ufuf(x)]=ufuf(y)

ans=0
for i in range(1,n+1):
    if ufuf(i)==ufuf(P[i-1]):
        ans+=1
print(ans)

Solution (Python):
import sys, re
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, tan, asin, acos, atan, radians, degrees, log2, gcd
from itertools import accumulate, permutations, combinations, combinations_with_replacement, product, groupby
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from bisect import bisect, bisect_left, insort, insort_left
from heapq import heappush, heappop
from functools import reduce
def input(): return sys.stdin.readline().strip()
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(): return list(map(int, input().split()))
def ZIP(n): return zip(*(MAP() for _ in range(n)))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7 

from decimal import *



class UnionFind():
    def __init__(self, n):
        self.n = n
        
        
        self.parents = [-1] * n
    def find(self, x):
        if 0 > self.parents[x]:
            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 0 > x]
    
    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()
p = LIST()

tree = UnionFind(N)

for _ in range(M):
	x, y = MAP()
	tree.union(x-1, y-1)

ans = 0
for i, x in enumerate(p):
	if tree.same(i, x-1):
		ans += 1

print(ans)

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

    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

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

n,m=map(int, input().split())
uf1=UnionFind(n)
p=list(map(int,input().split()))
for i in range(m):
    a,b=map(int, input().split())
    uf1.union(a-1,b-1)

for i in range(n):uf1.find(i) 
ans=0
for i in range(n):
    if uf1.par[i]==uf1.par[p[i]-1]:
        ans+=1
print(ans)

Solution (Python):
n,m=list(map(int,input().split()))
p=list(map(int,input().split()))
from collections import defaultdict
from collections import deque
c=0
for i in range(n):
    if p[i]==i+1:
        c+=1
vis=[0]*n
def dfs(x):
    vis[x]=1
    a.add(x+1)
    
    di = deque()
    di.append(x)
    while di:
        now = di.popleft()
        for j in d[now]:
            if not vis[j]:
                vis[j] = 1
                a.add(j+1)
                di.append(j)
    
    
    for u in d[x]:
        if vis[u]==0:
            dfs(u)
d=defaultdict(list)
for i in range(m):
    a,b=list(map(int,input().split()))
    d[a-1].append(b-1)
    d[b-1].append(a-1)
ans=0
for i in range(n):
    if vis[i]==0:
        a=set()
        dfs(i)
        l=0
        z=0
        for j in a:
            if p[j-1] in a:
                z+=1
            if p[j-1]==j:
                l+=1
        ans=max(ans,c+z-l)
print(ans)

Solution (Python):

class union_find:
    
    
    
    def __init__(self, N):
        self.par = [-1]*N

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

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

        if x == y:
            return False
        else:
            
            if self.par[x] > self.par[y]:
                x,y = y,x
            self.par[x] += self.par[y]
            self.par[y] = x
            return True

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

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

N, M = map(int, input().split())
P = list(map(lambda x:int(x)-1, input().split()))
uf = union_find(N)
for _ 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.same(P[i], 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_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())
Ps = [0] + list(map(int, input().split()))

uf = UnionFind(N+1)

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

rlt = 0
for i in range(1,N+1):
  if uf.find(i) == uf.find(Ps[i]):
    rlt += 1
  
print(rlt)

Solution (Python):
"""
初期状態でpiにいる数が、pi番目にたどり着けるかを判定すればよい。
unionFind木が使える
"""
N,M = map(int,input().split())
P = list(map(int,input().split()))
class UnionFind():
    def __init__(self,n):
        self.n=n
        self.parents = [i for i in range(n+1)]
        self.size = [1]*(n+1)
    def find(self,x):
        if self.parents[x]==x:
            return x
        else:
            self.parents[x]=self.find(self.parents[x])
            return self.parents[x]
    def unite(self,x,y):
        xRoot = self.find(x)
        yRoot = self.find(y)
        if xRoot == yRoot:
            return
        if self.size[xRoot]>self.size[yRoot]:
            self.parents[yRoot] = xRoot
            self.size[xRoot] += self.size[yRoot]
            self.size[yRoot] = 0
        else:
            self.parents[xRoot] = yRoot
            self.size[yRoot] += self.size[xRoot]
            self.size[xRoot] = 0
tree = UnionFind(N)
for _ in range(M):
    x,y = map(int,input().split())
    tree.unite(x,y)
cnt = 0
for i in range(N):
    p = P[i]
    if tree.find(i+1)==tree.find(p):
        cnt += 1

print(cnt)