CodeEff/ECCO huggingface dataset:
# Original solution
#!/usr/bin/env python3

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

Graph = [[] for _ in range(n)]
for x,y in xy:
    Graph[x-1].append(y-1)
    Graph[y-1].append(x-1)

check = [False for _ in range(n)]
def dfs(g,start,c,goal):
    c[start] = True
    if start == goal:
        return True
    for u in g[start]:
        if c[u]:
            continue
        if dfs(g,u,c,goal):
            return True
ans = 0
for i in range(n):
    c = check.copy()
    if dfs(Graph,i,c,p.index(i+1)):
        ans += 1
print(ans)


# Optimized solution
#!/usr/bin/env python3


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

#連結成分に属するかどうかを見るときはUnion-Findを用いる
#根(属するクラス)を返す関数
def root(x):
    if par[x] == x:
        return x
    par[x] = root(par[x])
    return par[x]
#同じクラスに属するかどうかを返す関数
def same(x,y):
    return root(x) == root(y)
#木を結合する関数
def union(x,y):
    x = root(x)
    y = root(y)
    #高さの高いほうに低いほうを結合
    if rank[x] < rank[y]:
        par[x] = y#xの親(属するクラス)をyとする
    else:
        par[y] = x
        if rank[x] == rank[y]:#高さが同じ場合
            rank[x] += 1#高さは1つ増える
par = [i for i in range(n)]
rank = [0 for _ in range(n)]
for i in range(m):
    x,y = list(map(int,input().split()))
    #swapできる頂点は同じ木にして同じ連結成分にする
    if not same(x-1,y-1):
        union(x-1,y-1)

ans = 0
for i in range(n):
    #p[i]とiが同じ連結成分ならばans+1
    if root(p[i]) == root(i):
        ans += 1
print(ans)
# Original solution
# -*- coding: utf-8 -*-
from collections import deque
from pprint import pprint
N, M = list(map(int, input().split()))
p = list(map(int, input().split()))
xy = [list(map(int, input().split())) for _ in range(M)]

graph = [[0 for _ in range(N)] for _ in range(N)]
visited = [0 for _ in range(N)]

for x,y in xy:
    graph[x-1][y-1] = 1
    graph[y-1][x-1] = 1

def dfs(v):
    que = deque()
    vis_list = []
    visited[v] = 1
    vis_list.append(v)
    que.append(v)
    while len(que) > 0:
        i = que.pop()   #深さ優先探索
        # i = que.popleft() #幅優先探索
        for n in range(N):
            if graph[i][n] == 1 and visited[n] == 0:
                visited[n] = 1
                vis_list.append(n)
                que.append(n)

    return vis_list

grps = []
for i in range(N):
    if visited[i] == 0:
        grps.append(dfs(i))

ans = 0
for g_list in grps:

    if len(g_list) == 1:
        if g_list[0] == p[g_list[0]]-1:
            ans += 1
    else:
        tmp = set([])
        for i in g_list:
            tmp.add(p[i]-1)
        ans += len( set(g_list) & tmp)

print(ans)


# Optimized solution
# -*- coding: utf-8 -*-
from collections import deque, defaultdict
N, M = list(map(int, input().split()))
p = list(map(int, input().split()))
xy = [list(map(int, input().split())) for _ in range(M)]

graph = defaultdict(set)
visited = [False for _ in range(N)]

for x,y in xy:
    graph[x-1].add(y-1)
    graph[y-1].add(x-1)

def dfs(v):
    que = deque()
    vis_list = []
    visited[v] = True
    vis_list.append(v)
    que.append(v)
    while len(que) > 0:
        i = que.pop()   #深さ優先探索
        # i = que.popleft() #幅優先探索
        for n in list(graph[i]):
            if visited[n] == False:
                visited[n] = True
                vis_list.append(n)
                que.append(n)

    return vis_list

grps = []
for i in range(N):
    if visited[i] == False:
        grps.append(dfs(i))

ans = 0
for g_list in grps:
    if len(g_list) == 1:
        if g_list[0] == p[g_list[0]]-1:
            ans += 1
    else:
        tmp = set([])
        for i in g_list:
            tmp.add(p[i]-1)
        ans += len( set(g_list) & tmp)

print(ans)
# Original solution
n,m=list(map(int,input().split()))
p=list(map(int,input().split()))
ans=0
import sys;sys.setrecursionlimit(10**9)
class u():#UnionFind f-根探し u-連結 s-連結? c-要素数
  def __init__(self,n):self.n,self.r=[-1]*n,[0]*n
  def f(self,x):
    if self.n[x]<0:return x
    else:self.n[x]=self.f(self.n[x]);return self.n[x]
  def u(self,x,y):
    x,y=self.f(x),self.f(y)
    if x==y:return
    elif self.r[x]>self.r[y]:self.n[x]+=self.n[y];self.n[y]=x
    else:self.n[y]+=self.n[x];self.n[x]=y;self.r[y]+=self.r[x]==self.r[y]
u=u(n)
for i in range(m):
  a,b=list(map(int,input().split()))
  u.u(a-1,b-1)
for i in range(n):
  if p[i]==i+1:ans+=1
  elif u.f(i)==u.f(p[i]-1):ans+=1
print(ans)

# Optimized solution
n,m=list(map(int,input().split()));p=list(map(int,input().split()));z=0;import sys;sys.setrecursionlimit(10**9);f=[i for i in range(n)]
def r(f,x):
  if f[x]!=x:f[x]=r(f,f[x])
  return f[x]
def u(f,a,b):
  x,y=r(f,a),r(f,b)
  if x!=y:f[x]=y
for i in range(m):a,b=list(map(int,input().split()));u(f,a-1,b-1)
for i in range(n):z+=r(f,i)==r(f,p[i]-1)
print(z)
# Original solution
from collections import deque
n, m = list(map(int, input().split()))
p = list(map(int, input().split()))
paths = {}
for _ in range(m):
    x, y = list(map(int, input().split()))
    if not x in list(paths.keys()):
        paths[x] = [y]
    else:
        paths[x].append(y)
    if not y in list(paths.keys()):
        paths[y] = [x]
    else:
        paths[y].append(x)

connected = [None]*(n+1)
path_id = 1
for i in range(1, n+1):
    if connected[i] is None:
        connected[i] = path_id
    else:
        continue

    if i in list(paths.keys()):
        stack = deque(paths[i])
        cluster = set([i]+paths[i])
    else:
        stack = []
    while len(stack) > 0:
        j = stack.pop()
        connected[j] = path_id
        for k in paths[j]:
            if connected[k] is None and not k in cluster:
                stack.append(k)
                cluster.add(k)
    path_id += 1
# print(connected)

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


# Optimized solution
from collections import deque
n, m = list(map(int, input().split()))
p = list(map(int, input().split()))
par = list(range(n+1))

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

for _ in range(m):
    x, y = list(map(int, input().split()))
    bx, by = find(x), find(y)
    par[y] = bx
    par[by] = bx

ans = 0
for i in range(1, n+1):
    if find(i) == find(p[i-1]):
        ans += 1
print(ans)
# Original solution
N,M=list(map(int,input().split()))
P_list=[int(p) for p in input().split()]
Tree=[-1]*N
def find(x):
  while Tree[x]>=0:
    x=Tree[x]
  return x
def unite(x,y):
  s1=find(x)
  s2=find(y)
  if s1==s2:
    pass
  else:
    if Tree[s1]<Tree[s2]:
      Tree[s2]=s1
    elif Tree[s2]>Tree[s1]:
      Tree[s1]=s2
    else:
      Tree[s1]+=-1
      Tree[s2]=s1
  return
for m in range(M):
  x,y=list(map(int,input().split()))
  unite(x-1,y-1)
ans=0
for i in range(N):
  if find(P_list[i]-1)==find(i):
    ans+=1
print(ans)
    
  

# Optimized solution
N,M=list(map(int,input().split()))
P_list=[int(p) for p in input().split()]
Tree=[i for i in range(N)]
def find(x):
  if x==Tree[x]:
    return x
  else:
    root=find(Tree[x])
    Tree[x]=root
    return root
def unite(x,y):
  s1=find(x)
  s2=find(y)
  if s1==s2:
    pass
  else:
    Tree[s1]=s2
for m in range(M):
  x,y=list(map(int,input().split()))
  unite(x-1,y-1)
ans=0
for i in range(N):
  if find(P_list[i]-1)==find(i):
    ans+=1
print(ans)
# Original solution
from copy import deepcopy

n, m = [int(i) for i in input().split()]
p = [int(i) for i in input().split()]
x = [[int(i) for i in input().split()] for j in range(m)]

x_ = deepcopy(x)
tree = []
memo = []

try:
    for i, y in enumerate(x_):
        if y in memo:
            continue
        tree.append(set(y))
        while True:
            prev = tree[i]
            for j in x_[i+1:]:
                if tree[i] & set(j):
                    tree[i] = tree[i] | set(j)
                    memo.append(j)

            if not tree[i] - prev:
                break
except:
    pass

for i in tree:
    i = list(i)
    temp = [p[j-1] for j in i]
    for j in i:
        if j in temp:
            p[j-1] = j

ans = 0

for i, p_ in enumerate(p):
    if i+1 == p_:
        ans += 1

print(ans)

# Optimized solution
n, m = [int(i) for i in input().split()]
p = [int(i) for i in input().split()]
x = [[int(i) for i in input().split()] for j in range(m)]

par = [i for i in range(0, n+1)]

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

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

for i in x:
    a, b = i
    unite(a, b)

ans = 0
for i, p_ in enumerate(p):
    if root(i+1) == root(p_):
        ans += 1

print(ans)
# Original solution
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

n,m=list(map(int,input().split()))
p=[int(i)-1 for i in input().split()]
tree=UnionFind(n)
for _ in range(m):
    x,y=list(map(int,input().split()))
    tree.union(x-1,y-1)

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

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

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

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

        if x == y:
            return

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

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

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

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

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

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

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

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

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

n,m=list(map(int,input().split()))
p=[int(i)-1 for i in input().split()]
tree=UnionFind(n)
for _ in range(m):
    x,y=list(map(int,input().split()))
    tree.union(x-1,y-1)

ans=0
for i in range(n):
    #print(p[i],tree.members(i))
    if tree.same(p[i],i):
        ans+=1
print(ans)
# Original solution
N,M=list(map(int,input().split()))
P=list(map(int,input().split()))

par=[i for i in range(N)]
rank=[1]*N

ans=0

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

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

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

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

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

print(ans)

# Optimized solution
N,M=list(map(int,input().split()))
P=list(map(int,input().split()))
par=[i for i in range(N)]
ans=0

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

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

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

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

print(ans)
# Original solution
class Unionfind:
    
    def __init__(self,n):
        self.uf = [-1]*n

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

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

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

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

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

l1 = [[] for i in range(n)]
l2 = [[] for i in range(n)]
for i in range(n):
    x = u.find(i)
    l1[x].append(i)
    l2[x].append(l[i]-1)
ans = 0
for i in range(n):
    a = set(l1[i])
    b = set(l2[i])
    ans += len(a&b)
print(ans)


# Optimized solution
class Unionfind:
    
    def __init__(self,n):
        self.uf = [-1]*n

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

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

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

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

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

ans = 0
for i in range(n):
    if u.same(i,l[i]-1):
        ans += 1
    
print(ans)
# Original solution
#!/usr/bin/env python3
import sys
input = sys.stdin.readline

class UnionFind():
    def __init__(self, n, m = None, read = 0):
        self.n = n
        self.parents = [-1] * n
        if read:
            if m is None:
                exit(print("Warning: What is M"))
            for i in range(m):
                a, b = map(int, input().split())
                self.union(a - 1, b - 1)

    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())
*p, = map(int, input().split())
UF = UnionFind(n, m, read = 1)

a = 0
for i in range(n):
    P = p[i] - 1
    if UF.same(P, i):
        a += 1
print(a)


# Optimized solution
#!/usr/bin/env python3
import sys
input = sys.stdin.readline

class UnionFind():
    def __init__(self, n, m = None, read = 0):
        self.n = n
        self.parents = [-1] * n
        if read:
            if m is None:
                raise ValueError("What is M")
            for i in range(m):
                a, b = list(map(int, input().split()))
                self.union(a - 1, b - 1)

    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 = list(map(int, input().split()))
*p, = list(map(int, input().split()))
UF = UnionFind(n, m, read = 1)

a = 0
for i in range(n):
    P = p[i] - 1
    if UF.same(P, i):
        a += 1
print(a)
# Original solution
n, m = list(map(int, input().split()))
P = tuple([int(x)-1 for x in input().split()])
swaps = [set() for _ in range(n)]
for i in range(m):
    x, y = tuple([int(x)-1 for x in input().split()])
    swaps[x].add(y)
    swaps[y].add(x)

c = 0
from collections import deque
for idx in range(n):
    q = deque([idx])
    visited = {idx}
    while q:
        i = q.pop()
        if idx == P[i]:
            c += 1
            break
        for s in swaps[i]:
            if not s in visited:
                visited.add(s)
                q.append(s)
print(c)


# Optimized solution
n, m = list(map(int, input().split()))
P = tuple([int(x)-1 for x in input().split()])
par = list(range(n))
size = [1] * n
def find(x):
    """ 根のノードの値を見つけて返す """
    if x != par[x]:
        par[x] = find(par[x])
    return par[x]

def unite(x, y):
    """xとyを結合する"""
    rootx = find(x)
    rooty = find(y)
    if rootx == rooty:
        return False
    else:
        if size[rootx] < size[rooty]:
            par[rootx] = rooty
            size[rooty] += size[rootx]
        else:
            par[rooty] = rootx
            size[rootx] += size[rooty]
        return True

def same(x, y):
    """ xとyが同じ集合に属しているか """
    return find(x) == find(y)

for _ in range(m):
    x, y = [int(x)-1 for x in input().split()]
    unite(x, y)
groups = {}
for idx, p in enumerate(par):
    p = find(p)
    groups.setdefault(p, set())
    groups[p].add(idx)

cnt = 0
for k, g in list(groups.items()):
    for gi in g:
        pi = P[gi]
        if pi in g:
            cnt += 1
print(cnt)
# Original solution
N,M = list(map(int,input().split()))
*P, = list(map(int,input().split()))
XY = [list(map(int,input().split())) for _ in [0]*M]

E = [[] for _ in [0]*N]
for x,y in XY:
    E[x-1].append(y-1)
    E[y-1].append(x-1)
    
def dist_bfs(N,E,start):
    d = [-1]*N
    d[start] = 0
    q = [start]
    while q:
        i = q.pop()
        di = d[i]
        for j in E[i]:
            if d[j]!=-1:continue
            d[j] = di+1
            q.append(j)
    return d

done = [False]*N
ans = 0
for i in range(N):
    if done[i]:continue
    d = dist_bfs(N,E,i)
    J = set(j for j in range(N) if d[j]>=0)
    PJ = set(P[j]-1 for j in J)
    ans += len(J & PJ)
    for j in J:
        done[j] = True
print(ans)

# Optimized solution
N,M = list(map(int,input().split()))
*P, = list(map(int,input().split()))
XY = [list(map(int,input().split())) for _ in [0]*M]

E = [[] for _ in [0]*N]
for x,y in XY:
    E[x-1].append(y-1)
    E[y-1].append(x-1)
    
def connect_bfs(N,E,start):
    connect = {start}
    q = [start]
    while q:
        i = q.pop()
        for j in E[i]:
            if j in connect:continue
            connect.add(j)
            q.append(j)
    return connect

done = [False]*N
ans = 0
for i in range(N):
    if done[i]:continue
    J = connect_bfs(N,E,i)
    PJ = set(P[j]-1 for j in J)
    ans += len(J & PJ)
    for j in J:
        done[j] = True
print(ans)
# Original solution
N,M = list(map(int,input().split()))
*P, = list(map(int,input().split()))
XY = [list(map(int,input().split())) for _ in [0]*M]

E = [[] for _ in [0]*N]
for x,y in XY:
    E[x-1].append(y-1)
    E[y-1].append(x-1)
    
def connect_bfs(N,E,start):
    connect = {start}
    q = [start]
    while q:
        i = q.pop()
        for j in E[i]:
            if j in connect:continue
            connect.add(j)
            q.append(j)
    return connect

done = [False]*N
ans = 0
for i in range(N):
    if done[i]:continue
    J = connect_bfs(N,E,i)
    PJ = set(P[j]-1 for j in J)
    ans += len(J & PJ)
    for j in J:
        done[j] = True
print(ans)

# Optimized solution
N,M = list(map(int,input().split()))
*P, = list(map(int,input().split()))
XY = [list(map(int,input().split())) for _ in [0]*M]

def get_Parent(n):
    if Parent[n] == -1:return n
    par = get_Parent(Parent[n])
    Parent[n] = par
    return par
def merge(x,y):
    x = get_Parent(x)
    y = get_Parent(y)
    if x!=y: Parent[y] = x
    return
def is_united(x,y):
    return get_Parent(x)==get_Parent(y)

Parent = [-1]*N
for x,y in XY:
    x-=1
    y-=1
    merge(x,y)
print((sum(is_united(i,p-1) for i,p in enumerate(P))))
# Original solution
n,m = list(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)

dp = [False]*n

ans = 0

for j in range(n):
    if dp[j]:
        continue
    check = [-1]*n
    check[j] = 0
    stack=[j]
    dp[j] = True
    while len(stack):
        v = stack.pop()
        for i in root[v]:
            if check[i] == -1:
                dp[i] = True
                check[i]=i
                stack.append(i)
    for k in range(n):
        if check[k] != -1 and check[p[k]-1] != -1:
            ans += 1

print(ans)

# Optimized solution
n,m = list(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

ans = 0

for j in range(n):
    if check[j] != -1:
        continue
    stack=[j]
    check[j]=j
    while len(stack):
        v = stack.pop(0)
        for i in root[v]:
            if check[i] == -1:
                check[i]=j
                stack.append(i)
for k in range(n):
    if check[k] == check[p[k]-1] :
        ans += 1

print(ans)
# Original solution
n, m = list(map(int, input().split()))
ps = [int(i) - 1 for i in input().split()]

neighbors = {v: [] for v in range(n)}
for _ in range(m):
    x, y = list(map(int, input().split()))
    neighbors[x - 1] += [y - 1]
    neighbors[y - 1] += [x - 1]


visited = [False] * n

def conn(i0):
    q = [i0]
    c = set([i0])
    while q:
        i = q.pop()
        visited[i] = True
        c.add(i)
        for n in neighbors[i]:
            if not visited[n]:
                q.append(n)
    return c


def nmatch(c):
    p = set([ps[i] for i in c])
    return len(p & c)


conns = []
for i in range(n):
    if not visited[i]:
        conns.append(conn(i))


answer = sum(nmatch(c) for c in conns)
print(answer)


# Optimized solution
n, m = list(map(int, input().split()))
ps = [int(i) - 1 for i in input().split()]
xy = [list(map(int, input().split())) for _ in range(m)]

dfind = {i: i for i in range(n)}


def find(v):
    visit = []
    while dfind[v] != v:
        visit.append(v)
        v = dfind[v]

    for i in visit:
        dfind[i] = v

    return v


def union(v0, v1):
    g0, g1 = find(v0), find(v1)
    g0, g1 = min(g0, g1), max(g0, g1)

    if g0 != g1:
        dfind[g1] = g0


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


nmatch = 0
for i, p in enumerate(ps):
    if find(i) == find(p):
        nmatch += 1

print(nmatch)