Buggy python submission (verdict: Time Limit Exceeded):
n, m = map(int, input().split())
P = tuple(map(lambda x:int(x)-1, input().split()))
swaps = [set() for _ in range(n)]
for i in range(m):
    x, y = tuple(map(lambda x:int(x)-1, input().split()))
    swaps[x].add(y)
    swaps[y].add(x)

c = 0
from collections import deque
for idx in range(n):
    q = deque([idx])
    visited = {idx}
    while q:
        i = q.pop()
        if idx == P[i]:
            c += 1
            break
        for s in swaps[i]:
            if not s in visited:
                visited.add(s)
                q.append(s)
print(c)


Fixed submission:
n, m = map(int, input().split())
P = tuple(map(lambda x: int(x)-1, input().split()))
par = list(range(n))
size = [1] * n
def find(x):
    """ 根のノードの値を見つけて返す """
    if x != par[x]:
        par[x] = find(par[x])
    return par[x]

def unite(x, y):
    """xとyを結合する"""
    rootx = find(x)
    rooty = find(y)
    if rootx == rooty:
        return False
    else:
        if size[rootx] < size[rooty]:
            par[rootx] = rooty
            size[rooty] += size[rootx]
        else:
            par[rooty] = rootx
            size[rootx] += size[rooty]
        return True

def same(x, y):
    """ xとyが同じ集合に属しているか """
    return find(x) == find(y)

for _ in range(m):
    x, y = map(lambda x: int(x)-1, input().split())
    unite(x, y)
groups = {}
for idx, p in enumerate(par):
    p = find(p)
    groups.setdefault(p, set())
    groups[p].add(idx)

cnt = 0
for k, g in groups.items():
    for gi in g:
        pi = P[gi]
        if pi in g:
            cnt += 1
print(cnt)

Buggy python submission (verdict: Time Limit Exceeded):
n, m = map(int, input().split())
P = tuple(map(lambda x:int(x)-1, input().split()))
swaps = [set() for _ in range(n)]
for i in range(m):
    x, y = tuple(map(lambda x:int(x)-1, input().split()))
    swaps[x].add(y)
    swaps[y].add(x)

c = 0
from collections import deque
for idx in range(n):
    q = deque([idx])
    visited = {idx}
    while q:
        i = q.pop()
        if idx == P[i]:
            c += 1
            break
        for s in swaps[i]:
            if not s in visited:
                visited.add(s)
                q.append(s)
    
print(c)


Fixed submission:
n, m = map(int, input().split())
P = tuple(map(lambda x: int(x)-1, input().split()))
par = list(range(n))
size = [1] * n
def find(x):
    """ 根のノードの値を見つけて返す """
    if x != par[x]:
        par[x] = find(par[x])
    return par[x]

def unite(x, y):
    """xとyを結合する"""
    rootx = find(x)
    rooty = find(y)
    if rootx == rooty:
        return False
    else:
        if size[rootx] < size[rooty]:
            par[rootx] = rooty
            size[rooty] += size[rootx]
        else:
            par[rooty] = rootx
            size[rootx] += size[rooty]
        return True

def same(x, y):
    """ xとyが同じ集合に属しているか """
    return find(x) == find(y)

for _ in range(m):
    x, y = map(lambda x: int(x)-1, input().split())
    unite(x, y)
groups = {}
for idx, p in enumerate(par):
    p = find(p)
    groups.setdefault(p, set())
    groups[p].add(idx)

cnt = 0
for k, g in groups.items():
    for gi in g:
        pi = P[gi]
        if pi in g:
            cnt += 1
print(cnt)