Buggy python submission (verdict: Time Limit Exceeded):
import sys

N, M = map(int, input().split())
p = list(map(int, input().split()))
pairs = [[int(c) for  c in l.strip().split()] for l in sys.stdin]

d1 = [set(pairs[0])]

for i in range(1,M):
  flag = -1
  for j in range(len(d1)):
    if len(d1[j] & set(pairs[i])) != 0:
      if flag != -1:
        d1[j] |= d1[flag]
        del d1[flag]
        break
      else:
        d1[j] |= set(pairs[i])
        flag = j
  if flag == -1:
    d1.append(set(pairs[i]))

ans = 0
for sub in d1:
  sub2 = {p.index(i)+1 for i in sub}
  ans += len(sub & sub2)

res = set(range(1,N+1))
for sub in d1:
  res -= sub

for c in res:
  if p[c-1] == c:
    ans += 1

print(ans)



Fixed submission:
import sys

N, M = map(int, input().split())
p = list(map(int, input().split()))
p.insert(0,0)
pairs = [[int(c) for  c in l.strip().split()] for l in sys.stdin]

link = [[] for _ in  range(N+1)]
for i in range(M):
  x = pairs[i][0]
  y = pairs[i][1]
  link[x].append(y)
  link[y].append(x)


ans = 0
visited = set()
#数列の１つ１つの数字について
for i in range(1, N+1):

  #既に1度見た数字は飛ばす
  if i in visited:
    continue
  
  #linkedに交換可能なひとまとまりの数字をセットとして格納
  #ここでlinkedをリセット
  linked = set()

  #todoにはリンク先を調べないといけない数字のリストを格納
  todo = [i]
  while todo:

    #todoから1つずつ
    cur = todo.pop()
    for dest in link[cur]:

      #既にグループに入っている数字は飛ばす
      if dest not in linked:
        linked.add(dest)
        todo.append(dest)

  #「位置」を表すグループと「数字」を表すグループのオーバーラップ部分を数える
  ans += len(linked & set(p[n] for n in linked))
  #一度見た数字は再訪しない
  visited |= linked

#最後にまだ一度も見ていない数字のなかで、i = p[i]であるものを探す
for i in set(range(1,N+1)) - visited:
  ans += i == p[i]

print(ans)

Buggy python submission (verdict: Time Limit Exceeded):
import sys

N, M = map(int, input().split())
p = list(map(int, input().split()))
pairs = [[int(c) for  c in l.strip().split()] for l in sys.stdin]

d1 = [set(pairs[0])]

for i in range(1,M):
  flag = -1
  flag2 = 0
  for j in range(len(d1)):
    if len(d1[j] & set(pairs[i])) != 0:
      if flag != -1:
        d1[j] |= d1[flag]
        del d1[flag]
        break
      else:
        d1[j] |= set(pairs[i])
        flag = j
  if flag == -1:
    d1.append(set(pairs[i]))

ans = 0
for i in range(N):
  if i+1 == p[i]:
    ans += 1
  else:
    for sub in d1:
      if p[i] in sub and i+1 in sub:
        ans += 1
        break

print(ans)


Fixed submission:
import sys

N, M = map(int, input().split())
p = list(map(int, input().split()))
p.insert(0,0)
pairs = [[int(c) for  c in l.strip().split()] for l in sys.stdin]

link = [[] for _ in  range(N+1)]
for i in range(M):
  x = pairs[i][0]
  y = pairs[i][1]
  link[x].append(y)
  link[y].append(x)


ans = 0
visited = set()
#数列の１つ１つの数字について
for i in range(1, N+1):

  #既に1度見た数字は飛ばす
  if i in visited:
    continue
  
  #linkedに交換可能なひとまとまりの数字をセットとして格納
  #ここでlinkedをリセット
  linked = set()

  #todoにはリンク先を調べないといけない数字のリストを格納
  todo = [i]
  while todo:

    #todoから1つずつ
    cur = todo.pop()
    for dest in link[cur]:

      #既にグループに入っている数字は飛ばす
      if dest not in linked:
        linked.add(dest)
        todo.append(dest)

  #「位置」を表すグループと「数字」を表すグループのオーバーラップ部分を数える
  ans += len(linked & set(p[n] for n in linked))
  #一度見た数字は再訪しない
  visited |= linked

#最後にまだ一度も見ていない数字のなかで、i = p[i]であるものを探す
for i in set(range(1,N+1)) - visited:
  ans += i == p[i]

print(ans)