CodeEff/ECCO huggingface dataset:
# Original solution
#coding:utf-8
n,m = list(map(int,input().split()))
List = list(map(int,input().split()))


forest = [i for i in range(n+1)]
rank = [0 for i in range(n+1)]

def unite(x,y):
    while forest[x] != x:
        x = forest[x]
    a = rank[x]
    
    while forest[y] != y:
        y = forest[y]
    b = rank[y]
    
    if a <= b:
        if a == b:
            rank[x] += 1
        forest[y] = x
    else:
        forest[x] = y


def Find(x):
    if forest[x] != x:
        rank[x] = 1
        forest[x] = Find(forest[x])
        return forest[x]
    else:
        return x
    
    for xi in Q:
        forest[xi] = x
        rank[xi] = 1
    
    return x

    
cnt = 0
for i in range(m):
    x,y = list(map(int,input().split()))
    unite(x,y)

for i in range(1,n+1):
    x = Find(i)
    y = Find(List[i-1])
    if x == y:
        cnt += 1
print(cnt)
    


# Optimized solution
#coding:utf-8
n,m = list(map(int,input().split()))
List = list(map(int,input().split()))


forest = [i for i in range(n+1)]
rank = [0 for i in range(n+1)]

def unite(x,y):
    x = Find(x)
    y = Find(y)
    a = rank[x]
    b = rank[y]
    forest[x] = y


def Find(x):
    if forest[x] != x:
        rank[x] = 1
        forest[x] = Find(forest[x])
        return forest[x]
    else:
        return x
    
    for xi in Q:
        forest[xi] = x
        rank[xi] = 1
    
    return x

    
cnt = 0
for i in range(m):
    x,y = list(map(int,input().split()))
    unite(x,y)

for i in range(1,n+1):
    x = Find(i)
    y = Find(List[i-1])
    if x == y:
        cnt += 1
print(cnt)
# Original solution
class UnionFind():
  def __init__(self,size):
    self.table=[-1for _ in range(size)]
  def root(self,x):
    while self.table[x]>=0:
      x=self.table[x]
    return x
  def unite(self,x,y):
    s1=self.root(x)
    s2=self.root(y)
    if s1!=s2:
      if self.table[s1]!=self.table[s2]:
        if self.table[s1]<self.table[s2]:
          self.table[s2]=s1
        else:
          self.table[s1]=s2
      else:
        self.table[s1]-=1
        self.table[s2]=s1
    return
  def same(self,x,y):
    return self.root(x)==self.root(y)
I=lambda:list(map(int,input().split()))
n,m=I()
p=I()
u=UnionFind(n)
for _ in range(m):
  a,b=I()
  u.unite(a-1,b-1)
print((sum(u.same(i,j-1)for i,j in zip(list(range(n)),p))))

# Optimized solution
I=lambda:list(map(int,input().split()));n,m=I();p=I();l=[i for i in range(n+1)]
def u(x):
 if l[x]!=x:l[x]=u(l[x])
 return l[x]
for _ in[0]*m:x,y=I();l[u(x)]=u(y)
print((sum(u(i)==u(j)for i,j in enumerate(p,1))))
# 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 i in range(m)]
c,d,e = [[] for i in range(n+1)],[True for i in range(n+1)],[]
d[0],ans = False,0
for i,j in x:
	c[i].append(j)
	c[j].append(i)
while sum(d)!=0:
	for i in range(n+1):
		if d[i]: break
	num2,numx,d[i] = set([i]),[i],False
	while True:
		num3 = set([])
		for i2 in list(num2):
			for j in c[i2]:
				if d[j]:
					num3.add(j)
					d[j] = False
		if len(num3)==0: break
		else:
			num2,num3 = deepcopy(num3),set([])
			for i in num2: numx.append(i)
	e.append(numx)
for i in e:
	for j in i:
		if p[j-1] in i: ans+=1
print(ans)

# Optimized solution
n,m = (int(i) for i in input().split())
par,rank = [i for i in range(n+1)],[0 for i in range(n+1)]
def root(x):
	if par[x]!=x: par[x] = root(par[x])
	return par[x]
def unite(x,y):
	x2,y2 = root(x),root(y)
	if x2!=y2:
		if rank[x2]<rank[y2]: par[x2] = y2
		else: par[y2] = x2
		if rank[x2]==rank[y2]: rank[x2]+=1
p = [int(i) for i in input().split()]
x = [[int(i) for i in input().split()] for i in range(m)]
for i,j in x: unite(i,j)
ans = -1
for i,j in enumerate([0]+p):
	if root(i)==root(j): 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 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 {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)
for i in range(N):
    P[i] -= 1
for _ in range(M):
    x, y = list(map(int, input().split()))
    x-=1
    y-=1
    UF.union(x, y)

print((sum(len(set(mem)&set(P[i] for i in mem)) for _, mem in list(UF.all_group_members().items()))))

# 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 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 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)
for i in range(N):
    P[i] -= 1
for _ in range(M):
    x, y = list(map(int, input().split()))
    x-=1
    y-=1
    UF.union(x, y)

print((sum(UF.same(i,p) for i,p in enumerate(P))))
# Original solution
n, m = list(map(int, input().split()))
pp = list(map(int, input().split()))
xyxy = [list(map(int, input().split())) for _ in range(m)]

class UnionFind(list) :
    def __init__(self, n) :
        super().__init__(list(range(n)))

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

    def union(self, x, y) :
        from copy import copy
        x = self.find(x)
        y = self.find(y)
        self.new = copy(self)
        self.new[y] = x
        return self.new

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

uf = UnionFind(n)
for x, y in xyxy :
    uf = uf.union(x-1, y-1)
for i in range(n) :
    uf.find(i)

d = {}
for i, k in enumerate(uf) :
    if k not in d :
        d[k] = {i}
    else :
        d[k].add(i)

e = {}
for k, set0 in list(d.items()):
    e[k] = set()
    for i in set0 :
        e[k].add(pp[i]-1)

ans = 0
for k in list(d.keys()) :
    set0 = d[k]
    set1 = e[k]
    ans += len(set0&set1)

print(ans)

# Optimized solution
n, m = list(map(int, input().split()))
pp = list(map(int, input().split()))
xyxy = [list(map(int, input().split())) for _ in range(m)]

class UnionFind(list) :
    def __init__(self, n) :
        super().__init__(list(range(n)))

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

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

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

uf = UnionFind(n)
for x, y in xyxy :
    uf.union(x-1, y-1)
for i in range(n) :
    uf.find(i)

d = {}
for i, k in enumerate(uf) :
    if k not in d :
        d[k] = {i}
    else :
        d[k].add(i)

e = {}
for k, set0 in list(d.items()):
    e[k] = set()
    for i in set0 :
        e[k].add(pp[i]-1)

ans = 0
for k in list(d.keys()) :
    set0 = d[k]
    set1 = e[k]
    ans += len(set0&set1)

print(ans)
# Original solution
n,m = list(map(int,input().split()))
p = list(map(int,input().split()))
info = [list(map(int,input().split())) for _ in range(m)]

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

# xの根を見つける
def root(x):
  if par[x] == x:
    return x
  else:
    par[x] = root(par[x])
    return par[x]
  
# x,yの根が同じかどうかを返す（根が同じ:True、根が異なる:False）
def find(x, y):
  return root(x) == root(y)

# xとyの根を結合させる
def union(x, y):
  x = root(x)
  y = root(y)
  if rank[x] < rank[y]:
    par[x] = y
  else:
    par[y] = x
    if rank[x] == rank[y]:
      rank[x] += 1

for i in range(m):
  union(info[i][0],info[i][1])

ans = 0

for i in range(n):
  if find(i+1,p.index(i+1)+1):
    ans += 1
    
print(ans)

# Optimized solution
n,m = list(map(int,input().split()))
p = list(map(int,input().split()))
info = [list(map(int,input().split())) for _ in range(m)]

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

# xの根を見つける
def root(x):
  if par[x] == x:
    return x
  else:
    par[x] = root(par[x])
    return par[x]
  
# x,yの根が同じかどうかを返す（根が同じ:True、根が異なる:False）
def find(x, y):
  return root(x) == root(y)

# xとyの根を結合させる
def union(x, y):
  x = root(x)
  y = root(y)
  if rank[x] < rank[y]:
    par[x] = y
  else:
    par[y] = x
    if rank[x] == rank[y]:
      rank[x] += 1

for i in range(m):
  union(info[i][0],info[i][1])

a=[0]*(n+1)
for i in range(n):
  a[p[i]]=i+1

ans = 0 
for i in range(1,n+1):
  if find(i,a[i]):
    ans += 1
    
print(ans)
# Original solution
import sys
 
n, m = [int(i) for i in input().split(" ")]
p = [0] + [int(i) for i in input().split(" ")]
par = [i for i in range(0, n + 1)]
id_set = [[i] for i in range(0, n + 1)]
p_set = [[p[i]] for i in range(0, n + 1)]

sys.setrecursionlimit(10**6)
 
def root(x):
    if par[x] == x:
        return x
    else:
        r = root(par[x])
        par[x] = r
        return r

def unite(x, y):
    x = root(x)
    y = root(y)
    if x == y:
        return
    else:
        par[x] = y
        id_set[y] = id_set[x] + id_set[y]
        p_set[y] = p_set[x] + p_set[y]

for i in range(0, m):
    x, y = [int(i) for i in input().split(" ")]
    unite(x, y)
    
s = 0
for i in range(1, n + 1):
    if i == root(i):
        id_i = sorted(id_set[i])
        p_i = sorted(p_set[i])
        k = 0
        for j in range(0, len(id_i)):
            while k < len(p_i) and p_i[k] < id_i[j]:
                k += 1
            if k >= len(p_i):
                break
            if p_i[k] == id_i[j]:
                s += 1

print(s)

# Optimized solution
import sys
 
n, m = [int(i) for i in input().split(" ")]
p = [0] + [int(i) for i in input().split(" ")]
par = [i for i in range(0, n + 1)]
id_set = [[] for i in range(0, n + 1)]
p_set = [[] for i in range(0, n + 1)]

sys.setrecursionlimit(10**6)
 
def root(x):
    if par[x] == x:
        return x
    else:
        r = root(par[x])
        par[x] = r
        return r

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

for i in range(0, m):
    x, y = [int(i) for i in input().split(" ")]
    unite(x, y)

for i in range(1, n + 1):
    r = root(i)
    id_set[r].append(i)
    p_set[r].append(p[i])
    
s = 0
for i in range(1, n + 1):
    if i == root(i):
        id_i = sorted(id_set[i])
        p_i = sorted(p_set[i])
        k = 0
        for j in range(0, len(id_i)):
            while k < len(p_i) and p_i[k] < id_i[j]:
                k += 1
            if k >= len(p_i):
                break
            if p_i[k] == id_i[j]:
                s += 1

print(s)
# Original solution
n,m=list(map(int,input().split()))
p=list([int(x)-1 for x in input().split()])
l=[list([int(x)-1 for x in input().split()]) for _ in [0]*m]
s=[0]*n
i=1
for x in l:
    if s[x[0]]==s[x[1]]==0:
        s[x[0]]=i
        s[x[1]]=i
        i+=1
    elif s[x[0]]==s[x[1]]>0:
        pass
    elif s[x[0]]==0:
        s[x[0]]=s[x[1]]
    elif s[x[1]]==0:
        s[x[1]]=s[x[0]]
    else:
        t=s[x[1]]
        for j in range(n):
            if s[j]==t:s[j]=s[x[0]]
list=list(set(s))
ans=0
if 0 in list:
    for j in range(n):
        if s[j]==0 and p[j]==j:ans+=1
    list.remove(0)
for j in list:
    ans+=len(set([p[k] for k in range(n) if s[k]==j])&set([k for k in range(n) if s[k]==j]))
print(ans)

# Optimized solution
n,m=list(map(int,input().split()))
p=list(map(int,input().split()))
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)
uf=UnionFind(n)
for _ in range(m):
    x,y=list(map(int,input().split()))
    uf.union(x,y)
ans=0
for i in range(n):
    if uf.same_check(i+1,p[i]):ans+=1
print(ans)
# Original solution
n,m = list(map(int,input().split()))
f = lambda x : int(x) - 1
p = list(map(f,input().split()))
par = [i for i in range(n)]

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

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

for i in range(m):
    x,y = list(map(f,input().split()))
    unite(x,y)

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

print(ans)

# Optimized solution
n,m = list(map(int,input().split()))
f = lambda x : int(x) - 1
p = list(map(f,input().split()))
par = [i for i in range(n)]

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

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

for i in range(m):
    x,y = list(map(f,input().split()))
    unite(x,y)

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

print(ans)
# Original solution
class UnionFind():
    def __init__(self,n):
        self.par=[i for i in range(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:
            self.par[x]=y

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

uf=UnionFind(n)
for pi in pair:
    uf.unite(pi[0],pi[1])

cnt=0
for i in range(n):
    if uf.same(i,p.index(i)):
        cnt+=1
print(cnt)



# Optimized solution
class UnionFind():
    def __init__(self,n):
        self.par=[i for i in range(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:
            self.par[x]=y

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

uf=UnionFind(n)
for pi in pair:
    uf.unite(pi[0],pi[1])

cnt=0
for i, pi in enumerate(p):
    if uf.same(i,pi):
        cnt+=1
print(cnt)
# Original solution
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 
        if self.root[x] > self.root[y]:
            x, y = y, x
        self.root[x] += self.root[y]
        self.root[y] = x 
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)
    def Count(self, x): # xが属するグループのサイズを返す
        return -self.root[self.Find_Root(x)]
    def Members(self, x): # xが属するグループに属する要素をリストで返す
        return [i for i in range(self.n) if self.Find_Root(i)==self.Find_Root(x)]
    def Roots(self): # 全ての根の要素をリストで返す
        return [i for i, x in enumerate(self.root) if x < 0]
    def Group_Count(self): # グループの数を返す
        return len(self.Roots())

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

# Optimized solution
import sys
input = sys.stdin.readline

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 
        if self.root[x] > self.root[y]:
            x, y = y, x
        self.root[x] += self.root[y]
        self.root[y] = x 
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)
    def Count(self, x): # xが属するグループのサイズを返す
        return -self.root[self.Find_Root(x)]
    def Members(self, x): # xが属するグループに属する要素をリストで返す
        return [i for i in range(self.n) if self.Find_Root(i)==self.Find_Root(x)]
    def Roots(self): # 全ての根の要素をリストで返す
        return [i for i, x in enumerate(self.root) if x < 0]
    def Group_Count(self): # グループの数を返す
        return len(self.Roots())
    
N, M = list(map(int, input().split()))
uf = UnionFind(N+1)
p = list(map(int, input().split()))
roots = {i:i for i in range(N)}
proots = {i:i for i in range(N)}
for _ in range(M):
    x, y = [int(x)-1 for x in input().split()]
    uf.Unite(x, y)

for i in range(N):
    r = uf.Find_Root(i)
    roots[i] = r
    proots[p[i]-1] = r 

ans = 0
for i in range(N):
    if roots[i] == proots[i]:
        ans += 1
print(ans)
# Original solution
I=lambda:[int(i) for i in input().split()]
n, m = I()
P = I()
D = {i:i for i in range(n+1)}

def U(x):
  if D[x] != x:
    D[x] = U(D[x])
  return D[x]

for _ in range(m):
  x, y = I()
  D[U(x)] = U(y)

print((sum(U(i)==U(p) for i, p in enumerate(P,1))))

# Optimized solution
I=lambda:[int(i)for i in input().split()]
n,m=I()
P=I()
D={i:i for i in range(n+1)}
def U(x):
  if D[x]!=x:D[x]=U(D[x])
  return D[x]
for _ in [0]*m:
  x,y=I();D[U(x)]=U(y)
print((sum(U(i)==U(p)for i,p in enumerate(P,1))))
# Original solution
def main():
    import sys
    input = sys.stdin.readline
    sys.setrecursionlimit(10**7)
    from collections import Counter, deque
    #from collections import defaultdict
    from itertools import combinations, permutations, accumulate, groupby, product
    from bisect import bisect_left,bisect_right
    from heapq import heapify, heappop, heappush
    from math import floor, ceil
    #from operator import itemgetter

    #inf = 10**17
    #mod = 10**9 + 7

    n,m = list(map(int, input().split()))
    p = list(map(int, input().split()))
    adj = [[] for _ in range(n)] #頂点数, 場合によって変える
    for _ in range(m):
        a,b = list(map(int, input().split()))
        adj[a-1].append(b-1)
        adj[b-1].append(a-1)

    swap = [[] for _ in range(n)]
    res = 0
    for i in range(n):
        if i == p[i]-1:
            res += 1
            continue
        d = deque([i])
        visited = [0]*n
        visited[i] = 1
        while d:
            v = d.popleft()
            for nv in adj[v]:
                if visited[nv] == 0:
                    if nv == p[i]-1:
                        res += 1
                    d.append(nv)
                    visited[nv] = 1
                    swap[i].append(nv)
    print(res)

if __name__ == '__main__':
    main()

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

    #inf = 10**17
    #mod = 10**9 + 7

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

    def find(x):
        if par[x] < 0:
            return x
        else:
            par[x] = find(par[x])
            return par[x]
    
    def unite(x,y):
        x = find(x)
        y = find(y)
        if x == y:
            return False
        else:
            if par[x] > par[y]:
                x,y = y,x
            par[x] += par[y]
            par[y] = x
            return True
    
    def same(x,y):
        return find(x) == find(y)
    
    par = [-1]*n

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

if __name__ == '__main__':
    main()