CodeEff/ECCO huggingface dataset:
# Original solution
n, m = list(map(int, input().split()))
ps = [int(p)-1 for p in input().split()]
xys = [tuple(int(x)-1 for x in input().split()) for _ in range(m)]

union = {node:(node, 0) for node in range(n)}

def root(node):
    if union[node][0] == node:
        return union[node]
    union[node] = root(union[node][0])
    return union[node]

def unite(*roots):
    r1, r2 = sorted(roots, key=lambda x:x[1])
    rank = max(r1[1]+1, r2[1])
    r = (r2[0], rank)
    union[r1[0]] = union[r2[0]] = r

for x, y in xys:
    unite(root(x), root(y))

print((sum(root(i) == root(p) for i, p in enumerate(ps))))

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

union = {node:node for node in range(n)}
depth = {node:0 for node in range(n)}

def root(node):
    if union[node] == node:
        return union[node]
    union[node] = root(union[node])
    return union[node]

for x, y in xys:
    a, b = sorted((root(x), root(y)), key=lambda z:depth[z])
    union[a] = b
    depth[b] = max(depth[b], depth[a]+1)

print((sum(root(i) == root(p) for i, p in enumerate(ps))))
# Original solution
N, M = list(map(int, input().split()))
sigma = list(map(int, input().split()))
gokans = []

for i in range(M):
    pair = tuple(map(int, input().split()))
    gokans.append(pair)

def connected(i, j, paths):
    if [pair for pair in paths if i in pair] and [pair for pair in paths if j in pair]:
        new_chain_i = [pair for pair in paths if i in pair]
        new_chain_j = [pair for pair in paths if j in pair]
        for pair in set(new_chain_i + new_chain_j):
            paths.remove(pair)
        narabi_i = set([couple[0] for couple in new_chain_i] + [couple[1] for couple in new_chain_i])
        narabi_j = set([couple[0] for couple in new_chain_j] + [couple[1] for couple in new_chain_j])
        if narabi_i & narabi_j != set():
            return True

        while new_chain_i and new_chain_j:
            new_chain_i_kari = []
            new_chain_j_kari = []

            for pair in new_chain_i:
                new_chain_i_kari += [couple for couple in paths if set(couple) & set(pair) != set()]
            for pair in new_chain_j:
                new_chain_j_kari += [couple for couple in paths if set(couple) & set(pair) != set()]
            new_chain_i = new_chain_i_kari
            new_chain_j = new_chain_j_kari

            for pair in set(new_chain_i + new_chain_j):
                paths.remove(pair)
            narabi_i = set([couple[0] for couple in new_chain_i] + [couple[1] for couple in new_chain_i])
            narabi_j = set([couple[0] for couple in new_chain_j] + [couple[1] for couple in new_chain_j])
            if narabi_i & narabi_j != set():
                return True
        return False
    else:
        return False

count = 0
for i in range(1, N+1):
    if i != sigma[i-1]:
        gokans1 = gokans.copy()
        if connected(i, sigma[i-1], gokans1):
            count += 1
    else:
        count += 1
print(count)

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

par = [i for i in range(n)]
#rootの計算量は、parが最初の状態に近いほど値は小さくて、高々O(n)
def root(x):
	tmp = par[x]
	if tmp == x:
		return x
	else:
		a = root(tmp)
		par[x] = a
		return a

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

for i in range(m):
	x, y = list(map(int, input().split()))
	merge(x-1, y-1)
	#print(par)

ans = 0

for i in range(n):
	if p[i]-1 == i:
		ans += 1
	elif root(p[i]-1) == root(i):
		ans += 1
print(ans)
# Original solution
import sys
input = sys.stdin.readline

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

from collections import deque

def bfs(u):
    d = [-1] * n
    queue = deque([u])
    d[u] = 0
    while queue:
        v = queue.popleft()
        for i in g[v]:
            if d[i] < 0:
                d[i] = d[v] + 1
                queue.append(i)
    return d

g = [[] for _ in range(n)]

for _ in range(m):
    x, y = [int(x) for x in input().split()]
    g[x - 1].append(y - 1)
    g[y - 1].append(x - 1)

ans = 0

for i, j in enumerate(p):
    # print(i, j)
    d = bfs(i)
    # print(d)
    if d[j - 1] >= 0:
        ans += 1

print(ans)


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

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

#xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]
#xとyの属する集合の併合
def unite(x,y):
    x = find(x)
    y = find(y)

    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

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

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

#初期化
#根なら-size,子なら親の頂点
par = [-1]*n

###具体例###
for _ in range(m):
    a, b = [int(x) for x in input().split()]
    unite(a - 1, b - 1)

ans = 0

for i, j in enumerate(p):
    if same(i, j - 1):
        ans += 1

print(ans)
# Original solution
N,M=list(map(int,input().split()))
p=list(map(int,input().split()))
p=[0]+p

par=[i for i in range(N+1)]
size=[1 for i in range(N+1)]

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

def union(x,y):
    if size[x]>size[y]:
        size[x]+=size[y]
        par[y]=find(x)
    elif size[y]>size[x]:
        size[y]+=size[x]
        par[x]=find(y)
    elif size[x]==size[y]:
        size[x]+=size[y]
        par[y]=find(x)
        
for i in range(M):
    a,b=list(map(int,input().split()))
    if find(a)==find(b):
        pass
    else:
        union(find(a),find(b))
#print(par)
ans=0
for i in range(1,N+1):
    if find(i)==find(p.index(i)):
        ans+=1
        #print(i,find(i))
print(ans)

# Optimized solution
N,M=list(map(int,input().split()))
p=list(map(int,input().split()))
p=[0]+p

par=[i for i in range(N+1)]
size=[1 for i in range(N+1)]

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

def union(x,y):
    if size[x]>size[y]:
        size[x]+=size[y]
        par[y]=find(x)
    elif size[y]>size[x]:
        size[y]+=size[x]
        par[x]=find(y)
    elif size[x]==size[y]:
        size[x]+=size[y]
        par[y]=find(x)
        
for i in range(M):
    a,b=list(map(int,input().split()))
    if find(a)==find(b):
        pass
    else:
        union(find(a),find(b))
#print(par)
ans=0
for i in range(1,N+1):
    if find(i)==find(p[i]):
        ans+=1
        #print(i,find(i))
print(ans)
# Original solution
from collections import deque
q = deque([])

def get_root(i):
    while True:
        if parent[i] == -1:
            return i
        i = parent[i]

def bfs(i):
    global l
    c = 0
    q.append(i)
    while True:
        if len(q) == 0:
            break
        p = q.popleft()
        l.append(p)
        c += 1
        if not children[p] == -1:
            for j in children[p]:
                q.append(j)
    return c

n, m = list(map(int, input().split()))
p = list(map(int, input().split()))
parent = [-1] * n
children = [-1] * n
d = [0] * n
root = []
rank = []
num = ["a"] * n
for _ in range(m):
    x, y = list(map(int, input().split()))
    x -= 1
    y -= 1
    if num[x] == "a":
        num[x] = [y]
    else:
        num[x].append(y)
    if num[y] == "a":
        num[y] = [x]
    else:
        num[y].append(x)
    if d[x] == d[y] == 0:
        root.append(x)
        rank.append(1)
        children[x] = [y]
        parent[y] = x
        d[x] = 1
        d[y] = 1
    elif d[x] == 1 and d[y] == 0:
        r = get_root(x)
        children[r].append(y)
        parent[y] = r
        d[y] = 1
    elif d[x] == 0 and d[y] == 1:
        r = get_root(y)
        children[r].append(x)
        parent[x] = r
        d[x] = 1
    else:
        s = get_root(x)
        t = get_root(y)
        if not s == t:
            i = rank[root.index(s)]
            j = rank[root.index(t)]
            if i >= j:
                parent[t] = s
                children[s].append(t)
                if i == j:
                    rank[root.index(s)] += 1
            else:
                parent[s] = t
                children[t].append(s)

ans = 0
for i in range(n):
    if parent[i] == -1 and children[i] != -1:
        l = []
        bfs(i)
        p0 = list(l)
        for j in l:
            pp = p[j] - 1
            p0.append(pp)
        k = len(p0)
        ans += k - len(set(p0))
    elif parent[i] == -1:
        if p[i] - 1 == i:
            ans += 1
print(ans)

# Optimized solution
def get_root(s):
    if s != root[s]:
        root[s] = get_root(root[s])
        return root[s]
    return s

def unite(s, t):
    root_s = get_root(s)
    root_t = get_root(t)
    if not root_s == root_t:
        if rank[s] == rank[t]:
            root[root_t] = root_s
            rank[root_s] += 1
        elif rank[s] > rank[t]:
            root[root_t] = root_s
        else:
            root[root_s] = root_t

def same(s, t):
    if get_root(s) == get_root(t):
        return True
    else:
        return False

n, m = list(map(int, input().split()))
p = list(map(int, input().split()))
root = [i for i in range(n)]
rank = [1 for _ in range(n)]
for _ in range(m):
    x, y = list(map(int, input().split()))
    unite(x - 1, y - 1)
ans = 0
for i in range(n):
    if get_root(i) == get_root(p[i] - 1):
        ans += 1
print(ans)
# Original solution
class unionFind():
	def __init__(self,n):
		self.tree=[-1]*n
	def find(self,x):
		if self.tree[x]<0:
			return x
		else:
			return self.find(self.tree[x])
	def union(self,x,y):
		xr=self.find(x)
		yr=self.find(y)
		if xr!=yr:
			if self.tree[xr]<self.tree[yr]:
				self.tree[yr]=xr
			elif self.tree[xr]>self.tree[yr]:
				self.tree[xr]=yr
			else:
				self.tree[xr]-=1
				self.tree[yr]=xr
			return True
		
		return False
def main():
	ans=0
	n,m=list(map(int,input().split()))
	a=unionFind(n)
	li=[x-1 for x in list(map(int,input().split()))]
	for _ in range(m):
		x,y=list(map(int,input().split()))
		a.union(x-1,y-1)
	for x in range(n):
		if a.find(x)==a.find(li[x]):
			ans+=1
	return ans
print((main()))


# Optimized solution
class unionFind():
	def __init__(self,n):
		self.tree=[-1]*n
	def find(self,x):
		if self.tree[x]<0:
			return x
		else:
			return self.find(self.tree[x])
	def union(self,x,y):
		xr=self.find(x)
		yr=self.find(y)
		if xr!=yr:
			if self.tree[xr]<self.tree[yr]:
				self.tree[yr]=xr
			elif self.tree[xr]>self.tree[yr]:
				self.tree[xr]=yr
			else:
				self.tree[xr]-=1
				self.tree[yr]=xr
			return True
		
		return False
def main():
	ans=0
	n,m=list(map(int,input().split()))
	a=unionFind(n)
	li=[x-1 for x in list(map(int,input().split()))]
	for _ in range(m):
		x,y=list(map(int,input().split()))
		a.union(x-1,y-1)
	for x in range(n):
		ans += a.find(x)==a.find(li[x])
	return ans
print((main()))
# Original solution
class unionFind():
	def __init__(self,n):
		self.tree=[-1]*n
	def find(self,x):
		if self.tree[x]<0:
			return x
		else:
			return self.find(self.tree[x])
	def union(self,x,y):
		xr=self.find(x)
		yr=self.find(y)
		if xr!=yr:
			if self.tree[xr]<self.tree[yr]:
				self.tree[yr]=xr
			elif self.tree[xr]>self.tree[yr]:
				self.tree[xr]=yr
			else:
				self.tree[xr]-=1
				self.tree[yr]=xr
			return True
		
		return False
def main():
	ans=0
	n,m=list(map(int,input().split()))
	a=unionFind(n)
	li=[x-1 for x in list(map(int,input().split()))]
	for _ in range(m):
		x,y=list(map(int,input().split()))
		a.union(x-1,y-1)
	for x in range(n):
		ans += a.find(x)==a.find(li[x])
	return ans
print((main()))


# Optimized solution
class unionFind():
	def __init__(self,n):
		self.tree=[-1]*n
	def find(self,x):
		if self.tree[x]<0:
			return x
		else:
			self.tree[x]=self.find(self.tree[x])
			return self.tree[x]
	def union(self,x,y):
		xr=self.find(x)
		yr=self.find(y)
		if xr!=yr:
			if self.tree[xr]<self.tree[yr]:
				self.tree[yr]=xr
			elif self.tree[xr]>self.tree[yr]:
				self.tree[xr]=yr
			else:
				self.tree[xr]-=1
				self.tree[yr]=xr
			return True
		
		return False
def main():
	ans=0
	n,m=list(map(int,input().split()))
	a=unionFind(n)
	li=[x-1 for x in list(map(int,input().split()))]
	for _ in range(m):
		x,y=list(map(int,input().split()))
		a.union(x-1,y-1)
	for x in range(n):
		ans += a.find(x)==a.find(li[x])
	return ans
print((main()))
# Original solution
from collections import deque

n,m = list(map(int,input().split()))
ps = [0] + list(map(int,input().split()))

memo = [[] for _ in range(n+1)]
connect = [[] for _ in range(n+1)]
visited = [0]*(n+1)

for i in range(m):
    x,y = list(map(int,input().split()))
    memo[x].append(y)
    memo[y].append(x)

for i in range(1,n+1):
    connect[i] = memo[i]
    que = deque(memo[i])
    while que:
        vtx = que.popleft()
        for num in memo[vtx]:
            if num not in connect[i]:
                que.append(num)
                connect[i].append(num)

for i in range(1,n+1):
    if ps[i] == i:
        continue
    else:
        pos = ps.index(i)
        if pos in connect[i]:
            ps[pos] = ps[i]
            ps[i] = i

cnt = 0
for i in range(1,n+1):
    if ps[i] != i:
        cnt += 1
print((n - cnt))

# Optimized solution
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 = list(map(int,input().split()))
ps = list(map(int,input().split()))
uf = UnionFind(n)
for i in range(m):
    x,y = list(map(int,input().split()))
    uf.union(x,y)

cnt = 0
for i,j in enumerate(ps):
    if uf.same_check(i+1 , j):
        cnt += 1
print(cnt)
# 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()))
pl = list(map(int,input().split()))
uf = UnionFind(n)
for _ in range(m):
   x,y = list(map(int,input().split()))
   uf.union(x-1,y-1)
ans = 0
for member in list(uf.all_group_members().values()):
   a = [pl[i]-1 for i in member]
   ans += len(set(a) & set(member))

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()))
pl = list(map(int,input().split()))
uf = UnionFind(n)
for _ in range(m):
   x,y = list(map(int,input().split()))
   uf.union(x-1,y-1)
ans = 0
for idx,p in enumerate(pl):
   ans += uf.same(p-1,idx)
print(ans)
# Original solution
N,M=list(map(int,input().split()))
e=[int(x)-1 for x in input().split()]
p=[i for i in range(N)]
r=[0]*N

def find(x):
	if p[x]!=x:
		p[x]=find(p[x])
	return p[x]

def unite(x,y):
	x=find(x)
	y=find(y)
	if x==y:
		return

	if r[x]<r[y]:
		p[x]=y
	else:
		p[y]=x
		if r[x]==r[y]:
			r[x]+=1

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

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

l=list()
for i in range(N):
	f=False	
	for j in l:
		if j[0]==find(i):
			j[1].add(i)
			f=True
			break
	if not f:
		l.append([find(i),set([i])])

c=0
for i in l:
	for j in i[1]:
		if e[j] in i[1]:
			c+=1

print(c)


# Optimized solution
N,M=list(map(int,input().split()))
e=[int(x)-1 for x in input().split()]
p=[i for i in range(N)]
r=[0]*N

def find(x):
	if p[x]!=x:
		p[x]=find(p[x])
	return p[x]

def unite(x,y):
	x=find(x)
	y=find(y)
	if x==y:
		return

	if r[x]<r[y]:
		p[x]=y
	else:
		p[y]=x
		if r[x]==r[y]:
			r[x]+=1

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

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

c=0
for i in range(N):
	if same(i,e[i]):
		c+=1

print(c)
# Original solution
N, M = list(map(int,input().split()))
P=list(map(int,input().split()))

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


Swap=[None]*M
for i in range(M):
    Swap[i]=sorted(map(int,input().split()))

def find(x):
    while Group[x] != x:
        x=Group[x]
    return x

for i in range(M):
    if find(Swap[i][1]) != find(Swap[i][0]):
        Group[find(Swap[i][1])]=min(find(Swap[i][1]),find(Swap[i][0]))
        Group[find(Swap[i][0])]=min(find(Swap[i][1]),find(Swap[i][0]))
        Group[Swap[i][1]]=min(find(Swap[i][1]),find(Swap[i][0]))
        Group[Swap[i][1]]=min(find(Swap[i][1]),find(Swap[i][0]))

count=0

for i in range(N):
    if find(P[i])==find(i+1):
        count+=1


print(count)


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

class Union_find():
    def __init__(self, N):
        self.Group = [i for i in range(N)]
        
    def find(self,x):# find(a)=find(b)のとき同じグループ
        while self.Group[x] != x:
            x = self.Group[x]
        return x

    def Union(self,x,y):  # xとyが同じグループになるよう更新
        if self.find(x) != self.find(y):
            self.Group[self.find(y)] = self.Group[self.find(x)] = min(self.find(y),self.find(x))

A = Union_find(N)

for x,y in S:
    A.Union(x-1,y-1)

ANS = 0

for i in range(N):
    P[i]-=1

for i in range(N):
    if A.find(i) == A.find (P[i]):
        ANS += 1

print(ANS)
# Original solution
n, m = list(map(int, input().split()))
p = list([int(x) - 1 for x in input().split()])
xy = [list([int(x) - 1 for x in 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)


# Optimized solution
n, m = list(map(int, input().split()))
p = list([int(x) - 1 for x in input().split()])
xy = [list([int(x) - 1 for x in 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)
# Original solution
# -*- coding: utf-8 -*-
import sys
sys.setrecursionlimit(10**9)
INF=10**18
MOD=10**9+7
input=lambda: sys.stdin.readline().rstrip()
YesNo=lambda b: bool([print('Yes')] if b else print('No'))
YESNO=lambda b: bool([print('YES')] if b else print('NO'))
int1=lambda x:int(x)-1

def main():
    N,M=map(int,input().split())
    p=list(map(int1,input().split()))
    edge=[[] for _ in range(N)]
    for _ in range(M):
        x,y=map(int1,input().split())
        edge[x].append((0,y))
        edge[y].append((0,x))
    from heapq import heappop,heappush
    def dijkstra(start,n,edges):
        d=[INF]*n
        used=[False]*n
        d[start]=0
        used[start]=True
        edgelist=[]
        for edge in edges[start]:
            heappush(edgelist,edge)
        while edgelist:
            minedge=heappop(edgelist)
            if used[minedge[1]]:
                continue
            v=minedge[1]
            d[v]=minedge[0]
            used[v]=True
            for edge in edges[v]:
                if not used[edge[1]]:
                    heappush(edgelist,(edge[0]+d[v],edge[1]))
        return d
    ans=0
    for i in range(N):
        d=dijkstra(i,N,edge)
        if d[p[i]]==0:
            ans+=1
    print(ans)

if __name__ == '__main__':
    main()


# Optimized solution
# -*- coding: utf-8 -*-
import sys
sys.setrecursionlimit(10**9)
INF=10**18
MOD=10**9+7
input=lambda: sys.stdin.readline().rstrip()
YesNo=lambda b: bool([print('Yes')] if b else print('No'))
YESNO=lambda b: bool([print('YES')] if b else print('NO'))
int1=lambda x:int(x)-1

def main():
    N,M=map(int,input().split())
    p=list(map(int1,input().split()))
    class UnionFind:
        def __init__(self,n):
            self.par=[i for i in range(n)]
            self.siz=[1]*n
            
        def root(self,x):
            while self.par[x]!=x:
                self.par[x]=self.par[self.par[x]]
                x=self.par[x]
            return x
        
        def unite(self,x,y):
            x=self.root(x)
            y=self.root(y)
            if x==y:
                return False
            if self.siz[x]<self.siz[y]:
                x,y=y,x
            self.siz[x]+=self.siz[y]
            self.par[y]=x
            return True
        
        def is_same(self,x,y):
            return self.root(x)==self.root(y)
        
        def size(self,x):
            return self.siz[self.root(x)]
    
    u=UnionFind(N)
    for _ in range(M):
        x,y=map(int1,input().split())
        u.unite(x,y)
    ans=0
    for i in range(N):
        if u.is_same(i,p[i]):
            ans+=1
    print(ans)

if __name__ == '__main__':
    main()