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, size):
        self.parent = list(range(size))
        self.rank = [0] * size

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

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

    def 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.unite(p[x], p[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, 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())
uf = UnionFind(n+1)
P = list(map(int, input().split()))
for _ in range(m):
    a, b = map(int, input().split())
    uf.union(a, b)

pos = dict()  
for i, p in enumerate(P):
    pos[p] = i+1
    
ans = 0
for i, p in enumerate(P):  
    if p == i + 1:  
        ans += 1
    else:  
        index = pos[i+1]
        if uf.same(i+1, index):
            ans += 1
print(ans)

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

par = [i for i in range(n)]
rank = [0 for _ in range(n)]


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


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


def union(x, y):
    x = root(x)
    y = root(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


for x, y in xy:
    union(x, y)

count = 0
for i, p_i in enumerate(p):
    count += 1 if is_same(i, p_i) else 0
print(count)

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

par = [i for i in range(n)]
rank = [0 for _ in range(n)]


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


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


def union(x, y):
    x = root(x)
    y = root(y)
    if x == y:
        return
    if rank[x] < rank[y]:
        par[x] = y
    else:
        par[y] = x
        if rank[y] == rank[x]:
            rank[x] += 1


for x, y in xy:
    union(x, y)

count = 0
for i, p_i in enumerate(p):
    count += 1 if is_same(i, p_i) else 0
print(count)

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

par = [i for i in range(n)]
rank = [0 for _ in range(n)]


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


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


def union(x, y):
    x = root(x)
    y = root(y)
    if x == y:
        return
    if rank[x] < rank[y]:
        par[x] = y
    else:
        par[y] = x
        if rank[y] == rank[x]:
            rank[y] += 1


for x, y in xy:
    union(x, y)

count = 0
for i, p_i in enumerate(p):
    count += 1 if is_same(i, p_i) else 0
print(count)

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

par = [i for i in range(n)]
rank = [0 for _ in range(n)]


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


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


def unite(x, y):
    x = root(x)
    y = root(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


for x, y in xy:
    unite(x - 1, y - 1)


count = 0
for i, p_i in enumerate(p):
    count += 1 if is_same(i, p_i - 1) else 0
print(count)

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

par = [i for i in range(n)]
rank = [1 for _ in range(n)]


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


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


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


for x, y in xy:
    unite(x - 1, y - 1)


count = 0
for i, p_i in enumerate(p):
    count += 1 if is_same(i, p_i - 1) else 0
print(count)

Solution (Python):
class UnionFind:
    def __init__(self, n: int):
        self.n = n
        self.parents = [-1] * n
    
    def find(self, x: int):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
    
    def union(self, x: int, y: int):
        x = self.find(x)
        y = self.find(y)
        
        if x == y:
            return
        if self.parents[y] < self.parents[x]:
            x, y = y, x
        
        self.parents[x] += self.parents[y]
        self.parents[y] = x
    
    def size(self, x: int):
        return -self.parents[self.find(x)]
    
    def same(self, x: int, y: int):
        return self.find(x) == self.find(y)
    
    def members(self, x: int):
        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 solve():
    N, M = map(int, input().split())
    p = list(map(lambda a: int(a) - 1, input().split()))
    uf_tree = UnionFind(N)
    for _ in range(M):
        x, y = map(lambda a: int(a) - 1, input().split())
        uf_tree.union(x, y)
    
    ans = 0
    for pi in p:
        if uf_tree.same(pi, p[pi]):
            ans += 1
    print(ans)


if __name__ == '__main__':
    solve()

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

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

Solution (Python):
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
sys.setrecursionlimit(500000)


class UnionFind(object):

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



N, M = map(int, readline().split())
P = list(map(int, readline().split()))

uf = UnionFind(N)

for _ in range(M):
    x, y = map(int, readline().split())
    x -= 1
    y -= 1
    if uf.find(x) != uf.find(y):
        uf.unite(x, y)

cnt = 0

for i in range(N):
    if uf.find(i) == uf.find(P[i]-1):
        cnt += 1

print(cnt)

Solution (Python):
import sys

sys.setrecursionlimit(10 ** 6)
int1 = lambda x: int(x) - 1
printV = lambda x: print(*x, sep="\n")
printH = lambda x: print(" ".join(map(str,x)))
def IS(): return sys.stdin.readline()[:-1]
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 LI1(): return list(map(int1, sys.stdin.readline().split()))
def LII(rows_number): return [II() for _ in range(rows_number)]
def LLI(rows_number): return [LI() for _ in range(rows_number)]
def LLI1(rows_number): return [LI1() for _ in range(rows_number)]

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 = MI()
	pp = LI1()
	uf = UnionFind(N)
	for _ in range(M):
		x,y = MI()
		x-=1
		y-=1
		uf.union(x,y)

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




if __name__ == '__main__':
	main()

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

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

def Unite(x, y, par, rank):
  x = Find(x, par)
  y = Find(y, par)

  if x != y:
    
    if rank[x] < rank[y]:
      par[y] += par[x]
      par[x] = y
    else:
      par[x] += par[y]
      par[y] = x
      if rank[x] == rank[y]:
        rank[x] += 1

def Same(x, y, par):
  return Find(x, par) == Find(y, par)

def Size(x, par):
  return -par[Find(x, par)]

n, m = map(int, input().split())
P = list(map(int, input().split()))
P = [p-1 for p in P]

par = [-1]* n
rank = [0]*n

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

ans = 0
for i in range(n):
    if P[i] == i:
        ans += 1
    else:
        if Same(i, P[i], par):
            ans += 1
print(ans)

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

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

def Unite(x, y, par, rank):
  x = Find(x, par)
  y = Find(y, par)

  if x != y:
    
    if rank[x] < rank[y]:
      par[y] += par[x]
      par[x] = y
    else:
      par[x] += par[y]
      par[y] = x
      if rank[x] == rank[y]:
        rank[x] += 1

def Same(x, y, par):
  return Find(x, par) == Find(y, par)

def Size(x, par):
  return -par[Find(x, par)]

n, m = map(int, input().split())
P = list(map(int, input().split()))
P = [p-1 for p in P]

par = [-1]* n
rank = [0]*n

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

ans = 0
for i in range(n):
    if P[i] == i:
        ans += 1
    else:
        if Same(i, P[i], par):
            ans += 1
print(ans)

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

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


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.union(x, y)

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

print(ans)

Solution (Python):


import sys
sys.setrecursionlimit(10**9)

def dfs(loc,num):
    root[loc]=num
    for item in plan[loc]:
        if root[item]==-1:
            dfs(item,num)
    return 0

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

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

plan=[[]for i in range(N)]
root=[-1]*N

for _ in range(M):
    a,b=map(int,input().split())
    plan[a-1].append(b-1)
    plan[b-1].append(a-1)

for i in range(N):
    if root[i]==-1:
        dfs(i,i)

ans=0
for i in range(N):
    if root[i]==root[P[i]-1]:
        ans+=1

print(ans)

Solution (Python):
import sys
input = sys.stdin.readline
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 solve():  
  n,m = (int(i) for i in input().split())
  p = list(int(i) for i in input().split())
  uf = UnionFind(n)
  for i in range(m):
    x,y = (int(i) for i in input().split())
    uf.union(x-1,y-1)
  ans = 0
  for i in range(n):
    number = p[i]
    if uf.same(i,number-1):
      ans += 1
  print(ans)
solve()

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

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


n, m = map(int, input().split())
P = list(map(int, input().split()))
XY = []
ans = 0

for _ in range(m):
    xy = list(map(int, input().split()))
    XY.append(xy)

UF = UnionFind(n)
for i in range(m):
    UF.union(P[XY[i][0]-1], P[XY[i][1]-1])

for j in range(n):
    if UF.same_check(j+1, P[j]):
        ans += 1

print(ans)

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

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

def find(a):
    if a==P[a]:
        return a
    else:
        return find(P[a])
        
def union(b,c):
    B=find(b)
    C=find(c)
    if S[B]<S[C]:
        P[B]=P[C]
        S[C]+=S[B]
    else:
        P[C]=P[B]
        S[B]+=S[C]
        
for i in range(M):
    x,y=map(int,input().split())
    union(x,y)

D={}

for i in range(1,N+1):
    D[p[i]]=i
    

ans=0
for i in range(1,N+1):
    if find(i)==find(D[i]):
        ans+=1
print(ans)

Solution (Python):
n,m = map(int,input().split())
a = list(map(lambda z:int(z)-1,input().split()))
pre = [i for i in range(n)]
for _ in range(m):
  x,y = map(lambda z:int(z)-1,input().split())
  while pre[x] != x:
    x = pre[x]
  while pre[y] != y:
    y = pre[y]
  if x == y:
    continue
  elif x < y:
    pre[y] = x
  else:
    pre[x] = y
home1 = [10**6 for _ in range(n)]
home2 = [10**6 for _ in range(n)]
for i in range(n):
  I = i
  while pre[I] != I:
    I = pre[I]
  home1[i] = I
  home2[a[i]] = I
ans = 0
for i in range(n):
  if home1[i] == home2[i]:
    ans += 1
print(ans)

Solution (Python):

n,m = map(int,input().split())
a = list(map(lambda x:int(x)-1,input().split()))
pre = [i for i in range(n)]
for _ in range(m):
  X,Y = map(int,input().split())
  X -= 1
  Y -= 1
  while pre[X] != X:
    X = pre[X]
  while pre[Y] != Y:
    Y = pre[Y]
  if X == Y:
    continue
  elif X < Y:
    pre[Y] = X
  else:
    pre[X] = Y


region = [[] for _ in range(n)]
ser = [[] for _ in range(n)]
for i in range(n):
  b = a[i]
  I = i
  while pre[I] != I:
    I = pre[I]
  region[I].append(b)
  ser[I].append(i)


home = [10**6 for _ in range(n)]
mother = [10**6 for _ in range(n)]
for i in range(n):
  for x in region[i]:
    home[x] = i
for i in range(n):
  for y in ser[i]:
    mother[y] = i


ans = []
for i in range(n):
  if home[i] == mother[i]:
    ans.append(i)

print(len(ans))

Solution (Python):

class UnionFind():
    """
    parents : 親要素(findしない場合は根ではないことの注意)，根の場合は"-(要素数）"
    find(x):要素xの属するグループの根を返す
    size(x):要素xの属するグループの要素数を返す
    same(x,y):x,yが同じグループに属しているか返す
    members(x):要素xが属するグループに属する要素をリストで返す
    roots:全ての根の要素を返す
    group_counte():グループの数を返す
    all_group_members():{根要素：[そのグループに含まれる要素のリスト]}の辞書を返す
    """
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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







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

uf = UnionFind(N)

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

Solution (Python):
import itertools
from collections import deque,defaultdict,Counter
from itertools import accumulate
import bisect
from heapq import heappop,heappush
from fractions import gcd
from copy import deepcopy
import math
import queue


Mod = 1000000007
import sys

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

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




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

Solution (Python):
import itertools
from collections import deque,defaultdict,Counter
from itertools import accumulate
import bisect
from heapq import heappop,heappush
from fractions import gcd
from copy import deepcopy
import math
import queue


Mod = 1000000007
import sys

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

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




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

Solution (Python):
class UnionFind():
   
   
   def __init__(self, n):
       self.n = n
       
       
       self.root = [-1]*(n+1)
       
       self.rnk = [0]*(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.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 isSameGroup(self, x, y):
       return self.Find_Root(x) == self.Find_Root(y)
   
   def Count(self, x):
       return -self.root[self.Find_Root(x)]

n,m=map(int,input().split())
p=[0]+list(map(int,input().split()))
h=UnionFind(n+1)
ans=0
for i in range(m):
    a,b=map(int,input().split())
    h.Unite(a,b)
for i in range(1,n+1):
    if h.isSameGroup(p[i],i):
        ans+=1
print(ans)

Solution (Python):
import itertools
from collections import deque,defaultdict,Counter
from itertools import accumulate
import bisect
from heapq import heappop,heappush
from fractions import gcd
from copy import deepcopy
import math
import queue


Mod = 1000000007
import sys

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

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




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

Solution (Python):
class UnionFind:
    """
    size の要素数の UnionFind を管理する
    data 中の負数の要素が根となる
    """

    def __init__(self, size):
        
        self.data = [-1] * size

    def merge(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x == y: return False

        
        if self.data[x] < self.data[y]:
            x, y = y, x

        
        self.data[y] += self.data[x]
        self.data[x] = y
        return True

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

    def size(self, x):
        """
        根は負数でデータ数を管理しているのでそれを返す
        """
        return -self.data[self.root(x)]

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


N, M = [int(_) for _ in input().split()]
uf = UnionFind(N+10)
P = [int(_) for _ in input().split()]
for i in range(M):
    x, y = [int(_) for _ in input().split()]
    uf.merge(x, y)
cnt = 0
for i, p in enumerate(P):
    cnt += uf.same(i + 1, p)
print(cnt)