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

def Find(x, par):
  if par[x] < 0:
    return x
  else:
    # 経路圧縮
    par[x] = Find(par[x], par)
    return par[x]

def Unite(x, y, par, rank):
  x = Find(x, par)
  y = Find(y, par)

  if x != y:
    # rankの低い方を高い方につなげる
    if rank[x] < rank[y]:
      par[y] += par[x]
      par[x] = y
    else:
      par[x] += par[y]
      par[y] = x
      if rank[x] == rank[y]:
        rank[x] += 1

def Same(x, y, par):
  return Find(x, par) == Find(y, par)

def Size(x, par):
  return -par[Find(x, par)]

par = [-1]* n
rank = [0]*n

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

ans = 0
for i in range(n):
    if Same(i, P[i], par):
        ans += 1
print(ans)

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

n, m = list(map(int, input().split()))
P = list(map(int, input().split()))
P = [p-1 for p in P]
def Find(x, par):
    if par[x] < 0:
        return x
    else:
        par[x] = Find(par[x], par)
        return par[x]

def Unite(x, y, par, rank):
    x = Find(x, par)
    y = Find(y, par)

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

def Same(x, y, par):
    return Find(x, par) == Find(y, par)

def Size(x, par):
    return -par[Find(x, par)]

par = [-1]* n
rank = [0]*n

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

ans = 0
for i, p in enumerate(P):
    if Same(i, p, par):
        ans += 1
print(ans)
# Original solution
n,m = list(map(int, input().split()))
p = list(map(int, input().split()))

l = [[0 for i in range(n)] for j in range(n)]

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

connect = []
v = []

for i in range(n):
    if i not in v:
        connect.append([i])
        v.append(i)
        stack =[i]
        visited = [i]
        while stack:
            q = stack.pop()
            for j in range(n):
                if l[q][j]==1 and j not in visited:
                    connect[-1].append(j)
                    visited.append(j)
                    stack.append(j)
                    v.append(j)

a = []
for i in range(len(connect)):
    a.append([])
    for j in connect[i]:
        a[-1].append(p[j]-1)

ans = 0

for i in range(len(connect)):
    ans += len(set(a[i]) & set(connect[i]))

print(ans)


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

l = [[] for j in range(n)]

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

connect = []
v = []

for i in range(n):
    if i not in v:
        connect.append([i])
        v.append(i)
        stack =[i]
        visited = [i]
        while stack:
            q = stack.pop()
            for j in range(len(l[q])):
                if l[q][j] not in visited:
                    connect[-1].append(l[q][j])
                    visited.append(l[q][j])
                    stack.append(l[q][j])
                    v.append(l[q][j])

a = []
for i in range(len(connect)):
    a.append([])
    for j in connect[i]:
        a[-1].append(p[j]-1)

ans = 0

for i in range(len(connect)):
    ans += len(set(a[i]) & set(connect[i]))

print(ans)
# Original solution
n,m = list(map(int, input().split()))
p = list(map(int, input().split()))

l = [[] for j in range(n)]

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

connect = []
a = []
v = []

for i in range(n):
    if i not in v:
        connect.append([i])
        a.append([p[i]-1])
        v.append(i)
        stack =[i]
        visited = [i]
        while stack:
            q = stack.pop()
            for j in range(len(l[q])):
                if l[q][j] not in visited:
                    connect[-1].append(l[q][j])
                    a[-1].append(p[l[q][j]]-1)
                    visited.append(l[q][j])
                    stack.append(l[q][j])
                    v.append(l[q][j])

ans = 0

for i in range(len(connect)):
    ans += len(set(a[i]) & set(connect[i]))

print(ans)


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

l = [[] for j in range(n)]

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

connect = []
a = []
v = [0 for i in range(n)]

for i in range(n):
    if v[i] == 0:
        connect.append([i])
        a.append([p[i]-1])
        v[i]=1
        stack =[i]
        while stack:
            q = stack.pop()
            for j in range(len(l[q])):
                if v[l[q][j]]==0:
                    connect[-1].append(l[q][j])
                    a[-1].append(p[l[q][j]]-1)
                    stack.append(l[q][j])
                    v[l[q][j]]=1

ans = 0

for i in range(len(connect)):
    ans += len(set(a[i]) & set(connect[i]))

print(ans)
# Original solution
from collections import defaultdict

class UnionFind(object):
  def __init__(self, n=1):
    self.par = [i for i in range(n)]
    self.rank = [0 for _ in range(n)]
    self.size = [1 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 union(self, x, y):
    x = self.find(x)
    y = self.find(y)
    if x != y:
      if self.rank[x] < self.rank[y]:
        x, y = y, x
      if self.rank[x] == self.rank[y]:
        self.rank[x] += 1
      self.par[y] = x
      self.size[x] += self.size[y]
  def is_same(self, x, y):
    return self.find(x) == self.find(y)
  def get_size(self, x):
    x = self.find(x)
    return self.size[x]


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

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

z = []
for i in range(M):
  t, s = list(map(int,input().split()))
  z.append((t,s))

uf = UnionFind(N)

for i in range(M):
  uf.union(z[i][0]-1, z[i][1]-1) #1というのは0番目のため1を引く。

#c = defaultdict(int)
ans = 0
for i in range(N):
  if uf.is_same(i, P[i]-1):
    ans += 1
print(ans)

# Optimized solution
class UnionFind(object):
    def __init__(self, n=1):
        self.par = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = [1 for _ in range(n)]
    def find(self, x):
        """
        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 と y のグループを結合
        """
        x = self.find(x)
        y = self.find(y)
        if x != y:
            if self.rank[x] < self.rank[y]:
                x, y = y, x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            self.par[y] = x
            self.size[x] += self.size[y]
    def is_same(self, x, y):
        """
        x と y が同じグループか否か
        """
        return self.find(x) == self.find(y)
    def get_size(self, x):
        """
        x が属するグループの要素数
        """
        x = self.find(x)
        return self.size[x]

    
N,M = list(map(int,input().split()))
P = list(map(int,input().split()))
uf = UnionFind(N)
for i in range(M):
    x,y = list(map(int,input().split()))
    x-=1;y-=1
    uf.union(x,y)
ans = 0
for i in range(N):
    now = P[i]-1
    loc = i
    if uf.is_same(now,loc):
        ans += 1
print(ans)
# Original solution
class Unionfind():  # 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 set(i for i in range(self.N) if self.find(i) == root)

    def roots(self):  # 根のリスト
        return set(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()))
xy = [list(map(int, input().split())) for _ in range(m)]

uf = Unionfind(n)
for x, y in xy:
    uf.union(x-1, y-1)

ans = 0
for lst in list(uf.all_group_members().values()):
    ans += sum((p[num] - 1 in lst) for num in lst)
print(ans)


# Optimized solution
class Unionfind():  # 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 all_group_members(self):  # グループごとの辞書
        members_dict = {i: set([i]) for i, x in enumerate(self.parents) if x < 0}
        for i, x in enumerate(self.parents):
            if x >= 0:
                members_dict[self.find(x)].add(i)
        return members_dict


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)
for x, y in xy:
    uf.union(x - 1, y - 1)

ans = 0
for lst in list(uf.all_group_members().values()):
    ans += sum((p[num] - 1 in lst) for num in lst)
print(ans)
# Original solution
class Unionfind():  # 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 all_group_members(self):  # グループごとの辞書
        members_dict = {i: set([i]) for i, x in enumerate(self.parents) if x < 0}
        for i, x in enumerate(self.parents):
            if x >= 0:
                members_dict[self.find(x)].add(i)
        return members_dict


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)
for x, y in xy:
    uf.union(x - 1, y - 1)

ans = 0
for lst in list(uf.all_group_members().values()):
    ans += sum((p[num] - 1 in lst) for num in lst)
print(ans)


# Optimized solution
class Unionfind():  # 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 groups(self):  # 全てのグループごとの要素
        members_dict = {}
        for i in range(self.N):
            if self.find(i) not in members_dict:
                members_dict[self.find(i)] = set()
            members_dict[self.find(i)].add(i)
        return members_dict


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)
for x, y in xy:
    uf.union(x - 1, y - 1)

ans = 0
for lst in list(uf.groups().values()):
    ans += sum((p[num] - 1 in lst) for num in lst)
print(ans)
# Original solution
class unionFind:
    def __init__(self, n, p):
        p = [0] + p + [0]*9
        self.data = [-1] * (n+10)
        self.sets = [set([i]) for i in range(n+10)]
        self.valsets = [set([p[i]])for i in range(n+10)]

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

    def unite(self, x, y):
        a, b = self.find(x), self.find(y)
        if a!=b:
            self.sets[b] |= self.sets[a]
            self.valsets[b] |= self.valsets[a]
            self.data[b] += self.data[a]
            self.data[a] = b


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

tree = unionFind(n, p)
for i in range(m):
    x, y = list(map(int, input().split()))
    tree.unite(x, y)

ans = -1
for i in range(n+1):
    if tree.data[i]<0:
        ans += len(tree.sets[i] & tree.valsets[i])
print(ans)

# Optimized solution
class unionFind:
    def __init__(self, n):
        self.data = [-1] * (n+10)

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

    def unite(self, x, y):
        a, b = self.find(x), self.find(y)
        if a!=b:
            self.data[b] += self.data[a]
            self.data[a] = b


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

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

ans = 0
for i in range(n):
    if tree.find(i+1)==tree.find(p[i]): ans += 1
print(ans)
# Original solution
import sys
sys.setrecursionlimit(10**9)


def unite(par, i, j):
    j = get_par(par, j)
    par[j] = get_par(par, i)

def get_par(par, p):
    while par[p] != p:
        p = par[p]
    return par[p]


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

for i in range(m):
    a,b = list(map(int, input().split()))
    aa = get_par(par, a)
    bb = get_par(par, b)
    if aa == bb:
        continue
    # unite
    unite(par, a, b)

ans = 0
for i in range(n):
    a = p[i]
    if get_par(par, a) == get_par(par, i+1):
        ans += 1
print(ans)


# Optimized solution
import sys
sys.setrecursionlimit(10**9)


def unite(par, i, j):
    j = get_par(par, j)
    par[j] = get_par(par, i)

def get_par(par, p):
    while par[p] != p:
        p = par[p]
    return par[p]


n,m = list(map(int, input().split()))
p = list(map(int, input().split()))
par = [i for i in range(n+1)]
cnt = [1 for _ in range(n+1)]

for i in range(m):
    a,b = list(map(int, input().split()))
    aa = get_par(par, a)
    bb = get_par(par, b)
    if aa == bb:
        continue
    # unite
    if cnt[aa] > cnt[bb]:
        par[bb] = aa
        cnt[aa] += cnt[bb]
    else:
        par[aa] = bb
        cnt[bb] += cnt[aa]

ans = 0
for i in range(n):
    a = p[i]
    if get_par(par, a) == get_par(par, i+1):
        ans += 1
print(ans)
# Original solution
def main():
    import sys
    input = sys.stdin.buffer.readline
    N, M = (int(i) for i in input().split())
    P = [int(i)-1 for i in input().split()]
    XY = [[int(i)-1 for i in input().split()] for j in range(M)]

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

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

    def is_same_group(x, y):
        return find_root(x) == find_root(y)

    def unite(x, y):
        x = find_root(x)
        y = find_root(y)
        if x == y:
            return
        if rank[x] < rank[y]:
            x, y = y, x
        rank[x] += rank[y]
        par[y] = x

    def size(x):
        # 連結成分のサイズを返す
        return rank[find_root(x)]

    for x, y in XY:
        unite(x, y)

    ans = 0
    for i, p in enumerate(P):
        if is_same_group(i, p):
            ans += 1
    print(ans)


if __name__ == '__main__':
    main()


# Optimized solution
def main():
    import sys
    input = sys.stdin.buffer.readline
    N, M = (int(i) for i in input().split())
    P = [int(i)-1 for i in input().split()]

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

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

    def is_same_group(x, y):
        return find_root(x) == find_root(y)

    def unite(x, y):
        x = find_root(x)
        y = find_root(y)
        if x == y:
            return
        if rank[x] < rank[y]:
            x, y = y, x
        rank[x] += rank[y]
        par[y] = x

    def size(x):
        return rank[find_root(x)]

    for i in range(M):
        a, b = (int(i)-1 for i in input().split())
        unite(a, b)

    ans = 0
    for i, p in enumerate(P):
        if is_same_group(i, p):
            ans += 1
    print(ans)


if __name__ == '__main__':
    main()
# Original solution
def main():
    import sys
    input = sys.stdin.buffer.readline
    N, M = (int(i) for i in input().split())
    P = [int(i)-1 for i in input().split()]

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

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

    def is_same_group(x, y):
        return find_root(x) == find_root(y)

    def unite(x, y):
        x = find_root(x)
        y = find_root(y)
        if x == y:
            return
        if rank[x] < rank[y]:
            x, y = y, x
        rank[x] += rank[y]
        par[y] = x

    def size(x):
        return rank[find_root(x)]

    for i in range(M):
        a, b = (int(i)-1 for i in input().split())
        unite(a, b)

    ans = 0
    for i, p in enumerate(P):
        if is_same_group(i, p):
            ans += 1
    print(ans)


if __name__ == '__main__':
    main()


# Optimized solution
def main():
    import sys
    input = sys.stdin.buffer.readline
    N, M = (int(i) for i in input().split())
    P = [int(i)-1 for i in input().split()]
    XY = [[int(i)-1 for i in input().split()] for j in range(M)]

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

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

    def is_same_group(x, y):
        return find_root(x) == find_root(y)

    def unite(x, y):
        x = find_root(x)
        y = find_root(y)
        if x == y:
            return
        if rank[x] < rank[y]:
            x, y = y, x
        rank[x] += rank[y]
        par[y] = x

    def size(x):
        return rank[find_root(x)]

    for x, y in XY:
        unite(x, y)

    ans = 0
    for i, p in enumerate(P):
        if is_same_group(i, p):
            ans += 1
    print(ans)


if __name__ == '__main__':
    main()
# 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()))
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.union(a, b)
  
cnt = 0
G = uf.all_group_members()
for i,w in enumerate(List):
  if uf.find(i+1) == uf.find(w):
    cnt += 1
  
print(cnt)

# Optimized 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)