CodeEff/ECCO huggingface dataset:
# Original solution
class UnionFindTree():
    
    def __init__(self, N):
        self.parent = [-1]*(N+1)
        self.rank = [1]*(N+1)
        self.size = [1]*(N+1)
  
    def find(self, i):
        if self.parent[i] == -1:
            group = i
        else:
            group = self.find(self.parent[i]) 
            self.parent[i] = group
        return group
      
    def unite(self, x, y):
        px = self.find(x)
        py = self.find(y)
        if px != py:
            if self.rank[px] == self.rank[py]: # rank is same
                self.rank[px] += 1
            elif self.rank[px] < self.rank[py]:
                px, py = py, px
                
            self.parent[py] = px
            self.size[px] += self.size[py]
    
    def getsize(self, x):
        return self.size[self.find(x)]
    
    def groups(self, index1=True):
        return set([self.find(i) for i in range(0+index1, N+index1)])
      
N,M = list(map(int,input().split()))
List=list(map(int,input().split()))

List2=[list(map(int,input().split())) for i in range(M)]
uf = UnionFindTree(N+1)

for i in range(M):
  a = List2[i][0]
  b = List2[i][1]  
  uf.unite(a, b)
  
cnt = 0
for i,w in enumerate(List):
  if uf.find(i+1) == uf.find(w):
    cnt += 1
  
print(cnt)

# Optimized solution
class UnionFind():
    # 作りたい要素数nで初期化
    # 使用するインスタンス変数の初期化
    def __init__(self, n):
        self.n = n
        # root[x]<0ならそのノードが根かつその値が木の要素数
        # rootノードでその木の要素数を記録する
        self.root = [-1]*(n+1)
        # 木をくっつける時にアンバランスにならないように調整する
        self.rnk = [0]*(n+1)

    # ノードxのrootノードを見つける
    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):
        # 入力ノードのrootノードを見つける
        x = self.Find_Root(x)
        y = self.Find_Root(y)
        # すでに同じ木に属していた場合
        if(x == y):
            return 
        # 違う木に属していた場合rnkを見てくっつける方を決める
        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
            # rnkが同じ（深さに差がない場合）は1増やす
            if(self.rnk[x] == self.rnk[y]):
                self.rnk[y] += 1
    # xとyが同じグループに属するか判断
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)

    # ノードxが属する木のサイズを返す
    def Count(self, x):
        return -self.root[self.Find_Root(x)]
      
N,M = list(map(int,input().split()))
List=list(map(int,input().split()))

List2=[list(map(int,input().split())) for i in range(M)]
uf = UnionFind(N+1)

for i in range(M):
  a = List2[i][0]
  b = List2[i][1]  
  uf.Unite(a, b)
  
cnt = 0
for i,w in enumerate(List):
  if uf.Find_Root(i+1) == uf.Find_Root(w):
    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()))
p = list([int(x)-1 for x in input().split()])
count = 0
uf = UnionFind(N)
for _ in range(M):
    i,j = [int(x)-1 for x in input().split()]
    uf.union(i,j)
dic = uf.all_group_members()
for i in range(N):
    if uf.same(p[i],i):
        count += 1
print(count)

# Optimized solution
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 = list(map(int,input().split()))
p = list([int(x)-1 for x in input().split()])
count = 0
uf = UnionFind(N)
for _ in range(M):
    i,j = [int(x)-1 for x in input().split()]
    uf.Unite(i,j)
for i in range(N):
    if uf.isSameGroup(p[i],i):
        count += 1
print(count)
# Original solution
def root(v):
    if v == par[v]:
        return v
    par[v] = root(par[v])
    return par[v]

def unite(u, v):
    u = root(u)
    v = root(v)
    if u == v:
        return
    if rank[u] < rank[v]:
        par[u] = v
    else:
        par[v] = u
        if rank[u] == rank[v]:
            rank[v] += 1

def same(u, v):
    u = root(u)
    v = root(v)
    if u == v:
        return 1
    return 0

N, M = list(map(int, input().split()))
P = list(map(int, input().split()))
par = list(range(N))
rank = [0] * N
for _ in range(M):
    x, y = list(map(int, input().split()))
    unite(x-1, y-1)

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

print(ans)



# Optimized solution
import sys
sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline

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

def unite(u, v):
    u = root(u)
    v = root(v)
    if u == v:
        return
    if rank[u] < rank[v]:
        u, v = v, u
    par[v] = u
    if rank[u] == rank[v]:
        rank[u] += 1

def connected(u, v):
    return 1 if root(u) == root(v) else 0

N, M = list(map(int, input().split()))
P = list(map(int, input().split()))
par = [i for i in range(N)]
rank = [0] * N
for _ in range(M):
    x, y = list(map(int, input().split()))
    unite(x-1, y-1)
res = 0
for i in range(N):
    res += connected(i, P[i]-1)
print(res)
# Original solution
N, M = list(map(int, input().split()))
p = list(map(int, input().split()))

set_list = []
edge = [[] for _ in range(N)]
for i in range(M):
    x, y = list(map(int, input().split()))
    x, y = x-1, y-1

    s1 = None
    s2 = None
    for i, se in enumerate(set_list):
        if x in se:
            s1 = se
            xi = i
        if y in se:
            s2 = se
            yi = i

    if s1 == None:
        if s2 == None:
            set_list.append({x, y})
        else:
            s2.add(x)
    else:
        if s2 == None:
            s1.add(y)
        elif s1 == s2:
            continue
        else:
            s = s1 | s2
            set_list.append(s)
            l = [xi, yi]
            l.sort()
            xi, yi = l
            del set_list[yi]
            del set_list[xi]

count = 0
for i in range(N):
    if p[i] == i+1:
        count += 1
    else:
        for se in set_list:
            if {i, p[i]-1} <= se:
                count += 1
                continue

print(count)


# Optimized solution
def root(R, a):
    if R[a] != a:
        R[a] = root(R, R[a])
    return R[a]

def union(R, x, y):
    a = root(R, x)
    b = root(R, y)
    if a != b:
        R[a] = b


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

R = [i for i in range(N)]
for i in range(M):
    x, y = list(map(int, input().split()))
    x, y = x-1, y-1
    union(R, x, y)

count = 0
for i in range(N):
    if root(R, i) == root(R, p[i] - 1):
        count += 1

print(count)
# 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()}


n, m = list(map(int, input().split()))
p_list = list(map(int, input().split()))
q_list = []
for item in p_list:
    q_list.append(item-1)

uni = UnionFind(n)

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

ret = 0

tmp_dict = uni.all_group_members()

for item in tmp_dict:
    t_list = tmp_dict[item]
    tmp = set()
    for var in t_list:
        tmp.add(q_list[var])
    ret += len(tmp & set(t_list))

print(ret)


# Optimized solution
class UnionFind():
    def __init__(self, n):
        self.parents = list(range(n))
        self.rank = [0] * n

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


n, m = list(map(int, input().split()))
p_list = list(map(int, input().split()))
q_list = list([x - 1 for x in p_list])

uni = UnionFind(n)

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

ret = 0

tmp_dict = dict()

for i in range(n):
    parent = uni.find(i)
    if parent in tmp_dict:
        tmp_dict[parent].append(i)
    else:
        tmp_dict[parent] = [i]

for item in tmp_dict:
    t_list = tmp_dict[item]
    tmp = set()
    for var in t_list:
        tmp.add(q_list[var])
    ret += len(tmp & set(t_list))

print(ret)
# Original solution
import queue
N,M=list(map(int,input().split()))
p=[int(i)-1 for i in input().split()]
x=[0 for i in range(M)]
y=[0 for i in range(M)]
edge=[set() for i in range(N)]
for i in range(M):
    x[i],y[i]=list(map(int,input().split()))
    x[i]-=1;y[i]-=1
    edge[x[i]].add(y[i])
    edge[y[i]].add(x[i])
k=0
L=[0 for i in range(N)]
q=queue.Queue()
reached=[0 for i in range(N)]
for i in  range(N):
    if reached[i]==1:
        continue
    k+=1
    q.put(i)
    reached[i]=1
    L[i]=k
    while(not(q.empty())):
        r=q.get()
        for v in edge[r]:
            if not(reached[v]):
                q.put(v)
                reached[v]=1
                L[v]=k
ans=0
for i in range(N):
    if L[i]==L[p[i]]:
        ans+=1
print(ans)


# Optimized solution
N,M=list(map(int,input().split()))
par=[0 for i in range(N)]
rnk=[0 for i in range(N)]
def init(n):
    for i in range(N):
        par[i]=i
        rnk[i]=0
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 (rnk[x]<rnk[y]):
        par[x]=y
    else:
        par[y]=x
        if(rnk[x]==rnk[y]):
            rnk[x]+=1
def same(x,y):
    return find(x)==find(y)

p=[int(i)-1 for i in input().split()]
init(N)
for i in range(M):
    x,y=list(map(int,input().split()))
    unite(x-1,y-1)
ans=0
for i in range(N):
    if same(i,p[i]):
        ans+=1
print(ans)
# Original solution
N, M = list(map(int, input().split()))
P = [int(p) for p in input().split()]

Par = [int(i) for i in range(N+1)]
Rank = [0 for i in range(N+1)]

def find(i, Par):
    if Par[i] == i:
        return i
    else:
        Par[i] = find(Par[i], Par)
        return Par[i]
def Unite(x, y):
    rx, ry = find(x, Par), find(y, Par)
    if rx == ry: return
    if Rank[rx] < Rank[ry]: Par[rx] = ry
    else: 
        Par[ry] = rx
        if Rank[rx] == Rank[ry]: Rank[rx] += 1
def Same(x, y): return find(x, Par) == find(y, Par)
    

for i in range(M):
    x, y = list(map(int, input().split()))
    x, y = min(x, y), max(x, y)
    Unite(x, y)
    
Count = 0
for i in range(N):
    Count += (1 if Same(P[i], i+1) else 0)
print(Count)

# Optimized solution
import sys

class UFT: #Union-find tree class
    def __init__(self, N): 
        self.tree = [int(i) for i in range(N)] 
        self.rank = [0 for i in range(N)]

    def find(self, a):
        if self.tree[a] == a: return a
        else:
            self.tree[a] = self.find(self.tree[a])
            return self.tree[a]

    def unite(self, a, b):
        a = self.find(a)
        b = self.find(b)
        if a == b: return
        if self.rank[a] < self.rank[b]: self.tree[a] = b
        else:
            self.tree[b] = a
            if self.rank[a] == self.rank[b]: self.rank[a] += 1

def solve():
    input = sys.stdin.readline
    N, M = list(map(int, input().split()))
    parent = UFT(N)
    P = [int(p) - 1 for p in input().split()]
    for i in range(M):
        x, y = list(map(int, input().split()))
        parent.unite(x-1, y-1)
    for i in range(N):
        parent.find(i)
        count = 0
    for i, p in enumerate(P):
        if parent.find(p) == parent.find(i): count += 1
    print(count)

    return 0

if __name__ == "__main__":
    solve()
# Original solution
def i1():
 return int(eval(input()))
def i2():
 return [int(i) for i in input().split()]
[n,m]=i2()
p=i2()

import sys
sys.setrecursionlimit(10000)

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

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

def un(x,y):
    x=rt(x)
    y=rt(y)
    if x==y:
       return
    else:
       if rank[x]<rank[y]:
          par[x]=y
       else:
          par[y]=x
          if rank[x]==rank[y]:
             rank[x]+=1
def find(x,y):
    return  rt(x)==rt(y)
       
for i in range(m):
 [x,y]=i2()
 un(x-1,y-1)

s=0
for i in range(n):
 if find(i,p[i]-1):
   s+=1
print(s)
   


# Optimized solution
def i1():
 return int(eval(input()))
def i2():
 return [int(i) for i in input().split()]
[n,m]=i2()
p=i2()

import sys
sys.setrecursionlimit(10000)

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

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

def un(x,y):
    x=rt(x)
    y=rt(y)
    if x==y:
       return
    else:
       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):
 [x,y]=i2()
 un(x-1,y-1)

s=0
for i in range(n):
 if rt(i)==rt(p[i]-1):
   s+=1
print(s)
# Original solution
import sys
sys.setrecursionlimit(100010)

def main():
    def input():
        return sys.stdin.readline()[:-1]

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

    p = list([int(x)-1 for x in input().split()])
    parent = [k for k in range(N)]

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

    def unite(x,y):
        parent[find(x)] = find(y)

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

    ans = 0
    for k in range(N):
        if find(k) == find(p[k]):
            ans += 1
    print(ans)

if __name__ == '__main__':
    main()


# Optimized solution
import sys
sys.setrecursionlimit(100010)

def main():
    def input():
        return sys.stdin.readline()[:-1]

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

    p = list([int(x)-1 for x in input().split()])
    parent = [k for k in range(N)]

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

    def unite(x,y):
        parent[find(x)] = find(y)

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

    ans = 0
    for k in range(N):
        if find(k) == find(p[k]):
            ans += 1
    print(ans)

if __name__ == '__main__':
    main()
# Original solution
# -*- coding: utf-8 -*-

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

    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 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
        else:
            self.par[y] = x
            if self.rank[x]==self.rank[y]:
                self.rank[x] += 1

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

n,m = list(map(int, input().split()))
p = [int(x) for x in input().split()]
uf = UnionFind(n+1)
for _ in range(m):
    x,y = list(map(int, input().split()))
    uf.unite(x,y)

cnt = 0
for i in range(1,n+1):
    if uf.same(i,p[i-1]):
        cnt += 1

print(cnt)


# Optimized solution
# -*- coding: utf-8 -*-

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.par = [-1 for _ in range(n)]

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

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

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

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

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

    def size(self,x):
        return -self.par[self.root(x)]

n,m = list(map(int, input().split()))
pl = list(map(int, input().split()))
uf = UnionFind(n+1)
for _ in range(m):
    x,y = list(map(int, input().split()))
    uf.unite(x,y)

res = 0
for i in range(n):
    if uf.same(i+1, pl[i]):
        res += 1

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

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

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

for g in list(uf.all_group_members().values()):
    e = []
    for i in g:
        e.append(P[i]-1)
    res += len(set(g) & set(e))

print(res)


# Optimized solution
N, M = list(map(int, input().split()))
P = list(map(int, input().split()))

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

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

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

for i, e in enumerate(P):
    if uf.same(i, e-1):
        res += 1

print(res)
# Original solution
#!/usr/bin/env python


class UnionFind:
    def __init__(self, size):
        self.table = list(range(size))

    def find(self, x):
        return self.table[x]

    def union(self, x, y):
        x1 = self.find(x)
        y1 = self.find(y)
        if x1 == y1:
            return False
        for i in range(len(self.table)):
            if self.table[i] == y1:
                self.table[i] = x1
        return True


n, m = list(map(int, input().split()))
ps = 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)
print((sum([uf.find(i) == uf.find(p - 1) for i, p in enumerate(ps)])))


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


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

    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 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
        else:
            self.par[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

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


n, m = list(map(int, input().split()))
ps = list(map(int, input().split()))
uf = UnionFind(n + 1)
for _ in range(m):
    x, y = list(map(int, input().split()))
    uf.unite(x, y)
print((sum([uf.same(i + 1, p) for i, p in enumerate(ps)])))
# Original solution
from collections import deque

def bfs(si, ei):
  q = deque()
  q.append(si)
  used = set([])
  while len(q) > 0:
    prvi = q.pop()
    for i in g[prvi]:
      if i in used: continue
      if i == ei: return True
      q.append(i)
      used.add(i)
  return False

N,M = list(map(int,input().split()))
P = [val-1 for val in map(int,input().split())]
g = {i:[] for i in range(N)}
ans = 0
for _ in range(M):
  x,y = list(map(int,input().split()))
  g[x-1].append(y-1)
  g[y-1].append(x-1)

for i in range(N):
  if i == P[i]: ans += 1
  elif bfs(i,P[i]): ans += 1
print(ans)

# Optimized solution
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 = list(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 = list(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)