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):
from bisect import bisect_left
def rt(i):
    while i!=G[i][0]:
        i = G[i][0]
    return i
N,M = map(int,input().split())
P = list(map(int,input().split()))
P.insert(0,0)
G = {i:[i,1] for i in range(1,N+1)}
for _ in range(M):
    x,y = map(int,input().split())
    rx = rt(x)
    ry = rt(y)
    if rx!=ry:
        if G[rx][1]>=G[ry][1]:
            G[ry][0] = rx
            G[rx][1] += G[ry][1]
        else:
            G[rx][0] = ry
            G[ry][1] += G[rx][1]
hist = [0 for _ in range(N+1)]
A = {}
for i in range(1,N+1):
    ri = rt(i)
    if hist[ri]==0:
        A[ri] = []
        hist[ri] = 1
    A[ri].append(i)
cnt = 0
for a in A:
    B = []
    for i in range(len(A[a])):
        B.append(P[A[a][i]])
    B = sorted(B)
    B.append(10**8)
    cur = 0
    for i in range(len(A[a])):
        if A[a][i]==B[cur]:
            cnt += 1
        elif A[a][i]<B[cur]:
            continue
        else:
            cur = bisect_left(B,A[a][i])
            if B[cur]==A[a][i]:
                cnt += 1
                cur += 1
print(cnt)

Solution (Python):
class UnionFind:
    def __init__(self, size):
        self.data = [-1] * size
    def root(self, x):
        if self.data[x] < 0:
            return x
        ans = self.root(self.data[x])
        self.data[x] = ans
        return ans
    def unite(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[x] += self.data[y]
        self.data[y] = x
        return True
    def same(self, x, y):
        return self.root(x) == self.root(y)
    def size(self, x):
        return -self.data[self.root(x)]

"""
Union-Find 森

https://scrapbox.io/data-structures/Union_Find

UnionFind(size):
0 ~ size - 1 がそれぞれ別々の集合に属するものとして初期化

root(x) -> void:
x が属する集合を表す根付き木の頂点を返す

unite(x) -> Bool:
root(x) と root(y) の間に辺を張り, x が属する集合と y が属する集合を結合する
変更があったかが返る (もともと同じ集合に属していたら False)

same(x, y) -> Bool:
x と y が同じ集合に属するか判定する

size(x) -> Int:
x が属する集合の要素数を返す

実装について
data[x] は data[x] < 0 のとき根であり, data[x] == -size(x) となっています
また, data[x] >= 0 のとき子であり, data[x] は親の番号を表しています
unite(x) は 
if self.data[x] > self.data[y]:
    x, y = y, x
で計算量が落ちます(データ構造をマージする一般的なテク)
root(x) は
self.data[x] = ans
で計算量が落ちます(経路圧縮)
"""




n, m = map(int, input().split())
p = list(map(int, input().split()))
for i in range(n):
    p[i] -= 1
uf = UnionFind(n)
for i in range(m):
    x, y = map(int, input().split())
    uf.unite(x - 1, y - 1)
ans = 0
for i in range(n):
    ans += uf.same(i, p[i])
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())
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(x, y)
ans = 0
for i in range(n):
  if uf.same(i, P[i]-1):
    ans += 1
print(ans)

Solution (Python):
n,m,*t=map(int,open(0).read().split())
u=[-1]*(n+1)
def root(x):
  while u[x]>=0:x=u[x]
  return x
def unite(x,y):
  x,y=root(x),root(y)
  if x==y:return
  if u[x]>u[y]:x,y=y,x
  u[x]+=u[y]
  u[y]=x
for x,y in zip(*[iter(t[n:])]*2):
  unite(x,y)
print(sum(root(i)==root(p)for i,p in enumerate(t[:n],1)))

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())
uf = UnionFind(N+1)

P = [int(i) for i in input().split()]

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

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

Solution (Python):
import collections
import sys


class unionFind:
    parent = []

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

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

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

    def unite(self, x, y):
        x, y = x-1, y-1
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return
        else:
            self.parent[x] = y
            return


input = sys.stdin.readline
N, M = map(int, input().split())
p = list(map(int, input().split()))
xy = [tuple(map(int, input().split())) for i in range(M)]
ans = 0
t = unionFind(N)

for x, y in xy:
    t.unite(x, y)

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

Solution (Python):
class UnionFind():
    def __init__(self, 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


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

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

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

print(ans)

Solution (Python):
class UnionFind():
    def __init__(self, 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


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

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

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

print(ans)

Solution (Python):
import sys
input = sys.stdin.readline
n,m=map(int, input().split(' '))
p = list(map(int, input().split(' ')))
ab = [list(map(int, input().split())) for i in range(m)]
graph = [[] for i in range(n+1)]
visited = [0]*(n+1)
conlist = [0]*(n+1)
for a,b in ab:
    graph[a].append(b)
    graph[b].append(a)
stack = []
cnt = 0
append = stack.append
pop = stack.pop
for i in range(1,n+1):
    if visited[i] != 1:
        cnt += 1
        append(i)
    while stack:
        x = pop()
        visited[x] = 1
        conlist[x] = cnt
        for y in graph[x]:
            if visited[y] != 1:
                append(y)
ans = 0
for i in range(1,n+1):
    if conlist[p[i-1]] == conlist[i]:
        ans+=1
print(ans)

Solution (Python):
N, M = map(int, input().split())
p = [int(i) for i in input().split()]
t = [[] for _ in range(N+1)]
for _ in range(M):
    x, y = [int(i) for i in input().split()]
    t[x].append(y)
    t[y].append(x)
l = [0]*(N+1)
stack = []
seen = [False]*(N+1)
c = 1
for i in range(1, N+1):
    if not seen[i]:
        stack.append(i)
        seen[i] = True
        c = i
    while len(stack):
        n = stack.pop()
        l[n] = c
        for v in t[n]:
            if not seen[v]:
                stack.append(v)
                seen[v] = True
ans = 0
for i, n in enumerate(p):
    if l[i+1] == l[n]:
        ans += 1
print(ans)

Solution (Python):
class UF_tree:
    def __init__(self, n):
        self.root = [-1] * (n + 1)  
        self.rank = [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 isSame(self, x, y):
        return self.find(x) == self.find(y)

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

    def getNodeLen(self, x):
        return -self.root[self.find(x)]


if __name__ == "__main__":
    n, m = map(int, input().split())
    p = tuple(map(int, input().split()))
    uf = UF_tree(n)
    for _ in range(m):
        x, y = map(int, input().split())
        uf.unite(x, y)

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

Solution (Python):
class UnionFind():
  def __init__(self, n):
    self.n = n
    self.parents = [-1] * n
    
  def find(self, x):
    if self.parents[x] < 0:
      return x
    else:
      self.parents[x] = self.find(self.parents[x])
      return self.parents[x]

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

    if x == y:
        return

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

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

  def 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()))
XY = [list(map(int, input().split())) for _ in range(M)]

uf = UnionFind(N)
for xy in XY:
  x, y = xy                       
  uf.union(x - 1, y - 1)
                         
ans = 0
for itr, val in enumerate(P):
  if itr == val - 1 or uf.same(itr, val - 1):
    ans+=1

print(ans)

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

ri = lambda: int(rs())
rl = lambda: list(map(int, stdin.readline().split()))
rs = lambda: stdin.readline().rstrip()  

N, M = rl()
P = rl()


def find(A, x):
    p = A[x]
    if p == x:
        return x
    a = find(A, p)
    A[x] = a
    return a


def union(A, x, y):
    if find(A, x) > find(A, y):
        bx, by = find(A, y), find(A, x)
    else:
        bx, by = find(A, x), find(A, y)
    
    A[by] = bx

V = [i for i in range(N+1)]
for i in range(M):
    x, y = rl()
    if find(V, x) != find(V, y):
        union(V, x, y)
index_set = [set() for _ in range(N+1)]
p_set = [set() for _ in range(N+1)]
answer = 0
for i in range(1, N+1):
    root = find(V, i)
    index_set[root].add(i)
    p_set[root].add(P[i-1])

for i in range(1, N+1):
    answer += len(index_set[i] & p_set[i])
print(answer)

Solution (Python):


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

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

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

        if x == y:
            return

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

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

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

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


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

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

Solution (Python):
class UnionFind():
  def __init__(self, x):
    self.x=x
    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 = list(map(lambda x : int(x)-1,input().split()))
count = 0
uf = UnionFind(N)
for _ in range(M):
    i,j = map(lambda x : int(x)-1,input().split())
    uf.Unite(i,j)
for i in range(N):
    if uf.isSameGroup(p[i],i):
        count += 1
print(count)

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

root = list(range(1, N+1))


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


for _ in range(M):
    x, y = map(int, input().split())
    x = find(x)
    y = find(y)
    root[max(x, y) - 1] = min(x, y)

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

Solution (Python):
N,M=map(int,input().split())
P=list(map(int,input().split()))
  
root=list(range(1,N+1))

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

for _ in range(M):
  x,y=map(int,input().split())
  x=find(x)
  y=find(y)
  if x!=y:
    root[max(x,y)-1]=min(x,y)
  
ans=0
for i in range(1,N+1):
  if find(i)==find(P[i-1]):
    ans+=1
  
print(ans)

Solution (Python):
from collections import deque

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 = [val-1 for val in map(int,input().split())]
ans = 0
uf = UnionFind(N)

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

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

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

class UnionFind():
  def __init__(self, x):
    self.x=x
    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)]

u=UnionFind(N)
for i in range(M):
  x,y=map(int,input().split())
  u.Unite(x,y)
ans=0
for i in range(N):
  if u.isSameGroup(i+1,p[i]):
    ans+=1
  else:
    continue
print(ans)

Solution (Python):
from collections import Counter,defaultdict,deque
import sys,bisect,math,itertools,string,queue,copy
from heapq import heappop, heappush
input = sys.stdin.readline
sys.setrecursionlimit(10**8)
mod = 10**9+7
 
def inp(): 
    return int(input())
def inpm(): 
    return map(int,input().split())
def inpl(): 
    return list(map(int, input().split()))
def inpls(): 
    return list(input().split())
def inplm(n): 
    return list(int(input()) for _ in range(n))
def inpll(n): 
    return sorted([list(map(int, input().split())) for _ in range(n)])
def sortx(x,n,k):
    if k == 0:x.sort(key=lambda y:y[1,n])
    else:x.sort(reversed=True, key=lambda y:y[1,n])
def graph():
    n,m=inpm()
    g=[[] for _ in range(n)]
    for _ in range(n-1):
        a,b=inpm()
        a-=1
        b-=1
        g[a].append(b)
        g[b].append(a)
    return n,m,g
 
def find(x): 
    if par[x]==x:
        return x
    else:
        par[x]=find(par[x])
        return par[x]
 
def unite(x,y): 
    x=find(x)
    y=find(y)
    if x==y:return
    if rank[x]<rank[y]:
        par[x]=y
    else:
        par[y]=x
        if rank[x]==rank[y]:
            rank[x]+=1
 
def same(x,y): 
    return find(x)==find(y)
 
def main():
    n,m=inpm()
    global par,rank
    par=[i for i in range(n)]  
    rank=[0 for _ in range(n)] 
    p=inpl()
    xy=[]
    for _ in range(m):
        x,y = inpm()
        if x>y:
            x,y=y,x
        xy.append([x,y])
    xy.sort()
    for i in range(m):
        x,y=xy[i]
        unite(x-1,y-1)
    groop=[[] for _ in range(n)]
    for i in range(n):
        groop[find(i)].append(i)
    ans=0
    for i in range(n):
        ps=[]
        for j in range(len(groop[i])):
            ps.append(p[groop[i][j]]-1)
        if ps==[]:
            continue
        else:
            ans+=len(set(ps)&set(groop[i]))
    print(ans)
 
if __name__ == "__main__":
    main()

Solution (Python):
def main():
    import sys
    input = sys.stdin.readline
    sys.setrecursionlimit(10**6)

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

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

        def root(self, x):
            if(self.tree[x] == x):
                return x
            self.tree[x] = self.root(self.tree[x])
            return self.tree[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
            self.tree[x] = y

    uf = UnionFind(n)

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


if __name__ == '__main__':
    main()

Solution (Python):
import sys, re
from collections import deque, defaultdict, Counter
from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians
from itertools import permutations, combinations, product
from operator import itemgetter, mul
from copy import deepcopy
from string import ascii_lowercase, ascii_uppercase, digits
from fractions import gcd
from bisect import bisect_left
import heapq

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()))
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
mod = 10 ** 9 + 7

N, M = MAP()
p = LIST()
xy = [LIST() for _ in range(M)]

class UnionFind:
   def __init__(self, n):
       self.par = [i for i in range(n+1)]
       self.rank = [0] * (n+1)
   
   def find(self, x):
       if self.par[x] == x:
           return x
       else:
           self.par[x] = self.find(self.par[x])
           return self.par[x]
   
   def union(self, x, y):
       x = self.find(x)
       y = self.find(y)
       if self.rank[x] < self.rank[y]:
           self.par[x] = y
       else:
           self.par[y] = x
           if self.rank[x] == self.rank[y]:
               self.rank[x] += 1
   
   def same_check(self, x, y):
       return self.find(x) == self.find(y)

tree = UnionFind(N)

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

ans = 0
for i in range(N):
	if i+1 == p[i]:
		ans += 1
	elif tree.same_check(i+1, p[i]):
		ans += 1
print(ans)

Solution (Python):
import sys
from collections import defaultdict

read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines


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


def unite(rank, par, x, y):
    x = root(par, x)
    y = root(par, y)

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

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


def main():
    N, M = map(int, readline().split())
    p = list(map(int, readline().split()))
    m = map(int, read().split())
    XY = list(zip(m, m))

    par = list(range(N))
    rank = [0] * N

    for x, y in XY:
        x -= 1
        y -= 1
        unite(rank, par, x, y)

    d_p = defaultdict(list)
    d_index = defaultdict(list)
    for i in range(N):
        par[i] = root(par, i)
        d_index[par[i]].append(p[i])
        d_p[par[i]].append(i+1)

    cnt = 0
    for i in set(par):
        cnt += len(list(set(d_index[i]) & set(d_p[i])))

    print(cnt)


main()

Solution (Python):
import sys
from collections import defaultdict

read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines


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


def unite(rank, par, x, y):
    x = root(par, x)
    y = root(par, y)

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

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


def main():
    N, M = map(int, readline().split())
    p = list(map(int, readline().split()))
    m = map(int, read().split())
    XY = list(zip(m, m))

    par = list(range(N))
    rank = [0] * N

    for x, y in XY:
        x -= 1
        y -= 1
        unite(rank, par, x, y)

    d_p = defaultdict(list)
    d_index = defaultdict(list)
    for i in range(N):
        par[i] = root(par, i)
        d_index[par[i]].append(p[i])
        d_p[par[i]].append(i+1)

    cnt = 0
    for i in set(par):
        cnt += len(list(set(d_index[i]) & set(d_p[i])))

    print(cnt)


main()

Solution (Python):

N,M = map(int,input().split())
P = list(map(int,input().split()))
XY = [list(map(int,input().split())) for i in range(M)]


class UF:
    def __init__(self,n):
        self.n = n
        self.root = [-1]*n 
        self.rank = [0]*n 
    def __del__(self):
        pass
        
    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
        
        if self.rank[x] < self.rank[y]:
            self.root[y] += self.root[x]
            self.root[x] = y
        else:
            self.root[x] += self.root[y]
            self.root[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) 
    
    def count(self,x):
        return -self.root[self.find(x)]
    
uf = UF(N)
for xy in XY:
    x,y = xy
    uf.unite(x-1,y-1)
    
ans = 0
for i,p in enumerate(P):
    if uf.same(p-1,i):
        ans+=1
        
print(ans)

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

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

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

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

Solution (Python):
N, M = map(int, input().split())

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

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

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

uf = UnionFind(N)

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

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

print(ans)

Solution (Python):
import sys
input = sys.stdin.readline
from heapq import heappush,heappop
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):
    if uf.same(i,p[i]-1):
      ans += 1
  print(ans)
    
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 func(x):
    return x - 1

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

    cnt = 0
    for i, p in enumerate(P):
        if uni.same(i,p):
            cnt += 1
    
    print(cnt)


if __name__ == "__main__":
    main()