Problem:
 Score : 400 points    Problem Statement We have a permutation of the integers from 1 through N , p_1 , p_2 , .., p_N .
We also have M pairs of two integers between 1 and N (inclusive), represented as (x_1,y_1) , (x_2,y_2) , .., (x_M,y_M) .
AtCoDeer the deer is going to perform the following operation on p as many times as desired so that the number of i ( 1  ≤  i  ≤  N ) such that p_i = i is maximized:   Choose j such that 1  ≤  j  ≤  M , and swap p_{x_j} and p_{y_j} .   Find the maximum possible number of i such that p_i = i after operations.      Constraints  2  ≤  N  ≤  10^5  1  ≤  M  ≤  10^5  p is a permutation of integers from 1 through N .  1  ≤  x_j,y_j  ≤  N  x_j  ≠  y_j  If i  ≠  j , \{x_i,y_i\}  ≠  \{x_j,y_j\} .  All values in input are integers.         Input Input is given from Standard Input in the following format:  N  M  p_1  p_2  ..  p_N  x_1  y_1  x_2  y_2  :  x_M  y_M       Output Print the maximum possible number of i such that p_i = i after operations.        Sample Input 1 5 2
5 3 1 4 2
1 3
5 4      Sample Output 1 2  If we perform the operation by choosing j=1 , p becomes 1 3 5 4 2 , which is optimal, so the answer is 2 .       Sample Input 2 3 2
3 2 1
1 2
2 3      Sample Output 2 3  If we perform the operation by, for example, choosing j=1 , j=2 , j=1 in this order, p becomes 1 2 3 , which is obviously optimal.
Note that we may choose the same j any number of times.       Sample Input 3 10 8
5 3 6 8 7 10 9 1 2 4
3 1
4 1
5 9
2 5
6 5
3 5
8 9
7 9      Sample Output 3 8       Sample Input 4 5 1
1 2 3 4 5
1 5      Sample Output 4 5  We do not have to perform the operation.

Solution (Python):
def solve():
  n, m = map(int,input().split())
  plst = list(map(int,input().split()))
  pare_inds = [i for i in range(n)]
  belongs = [[] for i in range(n)]
  
  def get_root(x):
    p = pare_inds[x]
    if p == x:
      return x
    a = get_root(p)
    pare_inds[x] = a
    return a
  
  for i in range(m):
    x, y = map(int,input().split())
    x, y = x - 1, y - 1
    r_x, r_y  = get_root(x), get_root(y)
    if r_x < r_y:
      pare_inds[y] = r_x
      pare_inds[r_y] = r_x
    else:
      pare_inds[x] = r_y
      pare_inds[r_x] = r_y
  
  for i in range(n):
    belongs[get_root(i)].append(i)
  
  
  ans = 0
  for lst in belongs:
    lst2 = [plst[i] - 1 for i in lst]
    lst.sort()
    lst2.sort()
    ind1 = 0
    ind2 = 0
    end = len(lst)
    while ind1 < end and ind2 < end:
      if lst[ind1] == lst2[ind2]:
        ans += 1
        ind1 += 1
        ind2 += 1
      elif lst[ind1] < lst2[ind2]:
        ind1 += 1
      else:
        ind2 += 1
  
  print(ans)
solve()

Solution (Python):
class DisjointSet:
    def __init__(self):
        self.rank = {}
        self.p = {}

    def makeSet(self, x):
        self.p[x] = x
        self.rank[x] = 0

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

    def unite(self, x, y):
        self.link(self.findSet(x), self.findSet(y))

    def link(self, x, y):
        if(self.rank[x] > self.rank[y]):
            self.p[y] = x
        else:
            self.p[x] = y
            if(self.rank[x] == self.rank[y]):
                self.rank[y] += 1

    def findSet(self, x):
        if(x != self.p[x]):
            self.p[x] = self.findSet(self.p[x])
        return self.p[x]

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

ds = DisjointSet()

for pi in p:
    ds.makeSet(pi)

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

ans = 0
for i,pi in enumerate(p):
    if ds.same(pi, i+1):
        ans += 1

print(ans)

Solution (Python):
N,M = map(int,input().split())
P = list(map(int,input().split()))

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 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
    def check(self, x, y):
        return self.find(x) == self.find(y)

uf = UnionFind(N)

for _ in range(M):
    x,y = map(int,input().split())
    uf.union(x,y)

Ans = 0
for i,p in enumerate(P,1):
    Ans += 1 if uf.check(i,p) else 0

print(Ans)

Solution (Python):
n, m = map(int, raw_input().split())
p = [-1] + map(int, raw_input().split())
parent = {i: i for i in range(1, n+1)}
def root(x):
    if parent[x] != x:
        parent[x] = root(parent[x])
    return parent[x]
for i in range(m):
    x, y = map(int, raw_input().split())
    rx = root(x)
    ry = root(y)
    rx, ry = sorted([rx, ry])
    parent[x] = rx
    parent[y] = rx
    parent[ry] = rx

D = {} 
for i in range(1, n+1):
    r = root(i)
    if not r in D:
        D[r] = (set(), set())
    D[r][0].add(i)
    D[r][1].add(p[i])
print sum([len(S & T) for S, T in D.values()])

Solution (Python):
N,M = map(int,input().split())
P = list(map(lambda x: int(x)-1,input().split()))

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 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
    def check(self, x, y):
        return self.find(x) == self.find(y)

uf = UnionFind(N)

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

Ans = 0
for i,p in enumerate(P):
    Ans += 1 if uf.check(i,p) else 0

print(Ans)

Solution (Python):
N, M = map(int, input().split())
init = list(map(int, input().split()))

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

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

for _ in range(M):
    a, b = map(int, input().split())
    pa, pb = map(get_parent, [a,b])
    if pa == pb:
        continue
    if depth[pa] < depth[pb]:
        pa, pb = pb, pa
        a, b = b, a
    parent[pb] = pa
    depth[pa] = max(depth[pa], depth[pb]+1)


index = [[] for _ in range(N+1)]
value = [[] for _ in range(N+1)]
for n in range(1, N+1):
    p = get_parent(n)
    index[p].append(n)
    value[p].append(init[n-1])

ans = 0
for n in range(1, N+1):
    idx, val = index[n], value[n]
    if idx:
        idx.sort()
        val.sort()
        i, j = 0, 0
        while i < len(idx) and j < len(idx):
            if idx[i] == val[j]:
                ans += 1
                i += 1
                j += 1
            elif idx[i] > val[j]:
                j += 1
            else:
                i += 1
print(ans)

Solution (Python):
N,M = map(int,input().split())
p = map(int,input().split())
graph = [[] for _ in range(N+1)]
for _ in range(M):
    x,y = map(int,input().split())
    graph[x].append(y)
    graph[y].append(x)

group = [0]*(N+1)
ans = 0

for i,num in enumerate(p,1):
    exploration_space = [i]
    for exploration_point in exploration_space:
        if group[exploration_point]:
            continue
        group[exploration_point] = i
        exploration_space.extend(graph[exploration_point])
    ans += (group[num] == group[i])

print(ans)

Solution (Python):
n, m = map(int, raw_input().split())
p = [-1] + map(int, raw_input().split())
edge = {i: [] for i in range(1, n+1)}
for i in range(m):
    x, y = map(int, raw_input().split())
    edge[x].append(y)
    edge[y].append(x)
ans = 0
used = [False] * (n+1)
for i in range(1, n+1):
    if used[i]:
        continue
    used[i] = True
    que = [i]
    S = set([i])
    T = set([p[i]])
    while que:
        u = que.pop(0)
        for v in edge[u]:
            if used[v]:
                continue
            que.append(v)
            used[v] = True
            S.add(v)
            T.add(p[v])
    ans += len(S & T)
print ans

Solution (Python):
import sys

sys.setrecursionlimit(2000000000)


class Node:
    def __init__(self, index):
        self.index = index
        self.connected_indices = set()


def build_graph(nodes, curr_index, connected_indices, reached_indices):
    
    if curr_index in connected_indices or curr_index in reached_indices:
        return

    connected_indices |= {curr_index}
    reached_indices |= {curr_index}

    unreached_indices = nodes[curr_index].connected_indices - connected_indices

    for i in unreached_indices:
        build_graph(nodes, i, connected_indices, reached_indices)

    return connected_indices


if __name__ == '__main__':
    N, M = map(int, input().split())
    p = [int(v) - 1 for v in input().split()]

    nodes = [Node(i) for i in range(N)]
    for _ in range(M):
        xy_str = input().split()
        x, y = int(xy_str[0]) - 1, int(xy_str[1]) - 1

        
        nodes[x].connected_indices |= {y}
        nodes[y].connected_indices |= {x}

    reached_indices = set()
    all_connected_indices = [None] * N
    for i in range(N):
        connected_indices = build_graph(nodes, i, set(), reached_indices)
        if connected_indices is None:
            continue

        for c in connected_indices:
            all_connected_indices[c] = connected_indices

    answer = sum([p[i] in all_connected_indices[i] for i in range(N)])
    print(answer)

Solution (Python):
import sys

sys.setrecursionlimit(2000000000)


class Node:
    def __init__(self, index):
        self.index = index
        self.connected_indices = set()

    def __repr__(self):
        return '{}: {}'.format(self.index, self.connected_indices)


def build_graph(nodes, curr_index, connected_indices, reached_indices):
    
    if curr_index in connected_indices or curr_index in reached_indices:
        return

    connected_indices |= {curr_index}
    reached_indices |= {curr_index}

    unreached_indices = nodes[curr_index].connected_indices - connected_indices

    for i in unreached_indices:
        build_graph(nodes, i, connected_indices, reached_indices)

    return connected_indices























if __name__ == '__main__':
    N, M = map(int, input().split())
    p = [int(v) - 1 for v in input().split()]

    nodes = [Node(i) for i in range(N)]
    for _ in range(M):
        xy_str = input().split()
        x, y = int(xy_str[0]) - 1, int(xy_str[1]) - 1

        nodes[x].connected_indices |= {y}
        nodes[y].connected_indices |= {x}

    reached_indices = set()
    all_connected_indices = [None] * N
    for i in range(N):
        connected_indices = build_graph(nodes, i, set(), reached_indices)
        if connected_indices is None:
            continue

        for c in connected_indices:
            all_connected_indices[c] = connected_indices

    answer = sum([p[i] in all_connected_indices[i] for i in range(N)])
    print(answer)

Solution (Python):
from sys import setrecursionlimit
setrecursionlimit(100000)

global visited,num,graph

def dfs(subtree):
    global visited,num,graph
    if visited[subtree] != 0:
        return

    visited[subtree] = num
    for node in graph[subtree]:
        if visited[node] != 0:
            continue
        dfs(node)

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

starting = list(map(int,input().split()))
graph = [[] for x in range(N+1)]
for i in range(M):
    a,b = map(int,input().split())
    graph[a].append(b)
    graph[b].append(a)

visited = [0 for x in range(N+1)]
num = 1
for i in range(1,N+1):
    if visited[i] == 0:
        dfs(i)
        num += 1

ans = 0
for i in range(1,N+1):
    if visited[i] == visited[starting[i-1]]:
        ans += 1

print(ans)

Solution (Python):
def d_equals(N, M, P, S):
    class UnionFind(object):
        def __init__(self, N):
            self.p = list(range(N))  
            self.rank = [0] * N  
            self.size = [1] * N  

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

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

        def union(self, x, y):  
            u = self.find(x)
            v = self.find(y)
            if u == v:  
                return
            if self.rank[u] < self.rank[v]:
                self.p[u] = v  
                self.size[v] += self.size[u]  
                self.size[u] = 0  
            else:
                
                self.p[v] = u
                self.size[u] += self.size[v]
                self.size[v] = 0
                if self.rank[u] == self.rank[v]:
                    
                    self.rank[u] += 1

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

        def show(self):
            return self.p

    p = [0] + P
    ans = 0
    uf = UnionFind(N + 1)
    for a, b in S:
        uf.union(a, b)  
    for i in range(1, N + 1):
        if uf.is_same(p[i], i):
            
            
            ans += 1
    return ans

N,M = [int(i) for i in input().split()]
P = [int(i) for i in input().split()]
S = [[int(i) for i in input().split()] for j in range(M)]
print(d_equals(N, M, P, S))

Solution (Python):
def d_equals(N, M, P, S):
    class UnionFind(object):
        def __init__(self, N):
            self.p = list(range(N))  
            self.rank = [0] * N  
            self.size = [1] * N  

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

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

        def union(self, x, y):  
            u = self.find(x)
            v = self.find(y)
            if u == v:  
                return
            if self.rank[u] < self.rank[v]:
                self.p[u] = v  
                self.size[v] += self.size[u]  
                self.size[u] = 0  
            else:
                
                self.p[v] = u
                self.size[u] += self.size[v]
                self.size[v] = 0
                if self.rank[u] == self.rank[v]:
                    
                    self.rank[u] += 1

    ans = 0
    uf = UnionFind(N)
    for a, b in S:
        uf.union(a - 1, b - 1)  
    for i in range(N):
        if uf.is_same(P[i] - 1, i):
            
            
            ans += 1
    return ans

N,M = [int(i) for i in input().split()]
P = [int(i) for i in input().split()]
S = [[int(i) for i in input().split()] for j in range(M)]
print(d_equals(N, M, P, S))

Solution (Python):
def d_equals(N, M, P, S):
    class UnionFind(object):
        def __init__(self, N):
            self.p = list(range(N))  
            self.rank = [0] * N  
            self.size = [1] * N  

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

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

        def union(self, x, y):  
            u = self.find(x)
            v = self.find(y)
            if u == v:  
                return
            if self.rank[u] < self.rank[v]:
                self.p[u] = v  
                self.size[v] += self.size[u]  
                self.size[u] = 0  
            else:
                
                self.p[v] = u
                self.size[u] += self.size[v]
                self.size[v] = 0
                if self.rank[u] == self.rank[v]:
                    
                    self.rank[u] += 1

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

        def show(self):
            return self.p

    ans = 0
    uf = UnionFind(N)
    for a, b in S:
        uf.union(a - 1, b - 1)  
    for i in range(N):
        if uf.is_same(P[i] - 1, i):
            
            ans += 1
    return ans

N,M = [int(i) for i in input().split()]
P = [int(i) for i in input().split()]
S = [[int(i) for i in input().split()] for j in range(M)]
print(d_equals(N, M, P, S))

Solution (Python):
def d_equals(N, M, P, S):
    class UnionFind(object):
        def __init__(self, N):
            self.p = list(range(N))  
            self.rank = [0] * N  
            self.size = [1] * N  

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

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

        def union(self, x, y):  
            u = self.find(x)
            v = self.find(y)
            if u == v:  
                return
            if self.rank[u] < self.rank[v]:
                self.p[u] = v  
                self.size[v] += self.size[u]  
                self.size[u] = 0  
            else:
                
                self.p[v] = u
                self.size[u] += self.size[v]
                self.size[v] = 0
                if self.rank[u] == self.rank[v]:
                    
                    self.rank[u] += 1

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

        def show(self):
            return self.p

    ans = 0
    uf = UnionFind(N)
    for a, b in S:
        uf.union(a - 1, b - 1)  
    for i in range(N):
        if uf.is_same(P[i] - 1, i):
            
            ans += 1
        elif P[i] - 1 == i:
            
            ans += 1
    return ans

N,M = [int(i) for i in input().split()]
P = [int(i) for i in input().split()]
S = [[int(i) for i in input().split()] for j in range(M)]
print(d_equals(N, M, P, S))

Solution (Python):
from collections import defaultdict
N,M=map(int, raw_input().split())
p=map(int, raw_input().split())



a = []
for i in range(M):
	x,y=map(int,raw_input().split())
	if x<=y: a.append((x-1,y-1))
	else: a.append((y-1,x-1))

a=sorted(a, key=lambda x: x[0])



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

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

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


def unite(x,y):
	x=root(x)
	y=root(y)
	if x==y:
		return
	elif x<=y:
		par[y]=x
	else:
		par[x]=y


for x,y in a:
	if not same(x,y):
		unite(x,y)


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

Solution (Python):


n, m = map(int, input().split())
p = [int(i) for i in input().split()]
pairs = [[int(i) for i in input().split()] for _ in range(m)]

parents = [i for i in range(n + 1)]

def ufRoot(a):
    global parents
    if parents[a] == a:
        return(a)
    else:
        parents[a] = ufRoot(parents[a])
        return parents[a]

def ufFind(a, b):
    return ufRoot(a) == ufRoot(b)

def ufUnite(a, b):
    global parents
    a = ufRoot(a)
    b = ufRoot(b)
    if (a == b):
        return
    parents[a] = b

for pp in pairs:
    if ufFind(pp[0], pp[1]) == False:
        ufUnite(pp[0], pp[1])

for i in range(len(parents)):
    parents[i] = ufRoot(parents[i])


uniques = list(set(parents))
dict_ids = {}
dict_values = {}

for u in uniques:
    dict_ids[u] = []
    dict_values[u] = []

for i in range(n):
    dict_ids[parents[i + 1]].append(i + 1)
    dict_values[parents[i + 1]].append(p[i])

res = 0
for u in uniques:
    sets = set(dict_ids[u]).intersection(dict_values[u])
    res += len(sets)

print(res)

Solution (Python):
n, m = [int(i) for i in input().split()]
p = [int(i) for i in input().split()]
x = [[int(i) for i in input().split()] for j in range(m)]

par = [i for i in range(0, n+1)]

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

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

for i in x:
    a, b = i
    unite(a, b)

ans = 0
for i, p_ in enumerate(p):
    if root(i+1) == root(p_):
        ans += 1

print(ans)

Solution (Python):
n, m = map(int, input().split())
p = list(map(int, input().split()))
idx = [0]*(n+1)
for i, v in enumerate(p, 1):
    idx[v] = i
par = list(range(n+1))
sz = [1]*(n+1)
def union(i, j):
    i = find(i)
    j = find(j)
    if sz[i] > sz[j]:
        i, j = j, i
    par[i] = par[j]
    sz[j] += sz[i]
def find(i):
    if par[i] == i:
        return i
    par[i] = find(par[i])
    return par[i]
for _ in range(m):
    x, y = map(int, input().split())
    union(x, y)
print(sum(find(idx[i]) == find(i) for i in range(1, n+1)))

Solution (Python):


class UnionFind3:
    def __init__(self, size):
        
        
        self.table = [-1 for _ in range(size)]

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

    
    def union(self, x, y):
        s1 = self.find(x)
        s2 = self.find(y)
        if s1 != s2:
            if self.table[s1] <= self.table[s2]:
                
                self.table[s1] += self.table[s2]
                self.table[s2] = s1
            else:
                self.table[s2] += self.table[s1]
                self.table[s1] = s2
            return True
        return False


N, M = [int(i) for i in input().split()]
p = [int(i) - 1 for i in input().split()]

uf = UnionFind3(N + 1)
for i in range(M):
    x, y = [int(i)-1 for i in input().split()]
    uf.union(x, y)

count = 0
for i in range(N):
    if p[i] != i:
        if uf.find(p[i]) == uf.find(i):
            count += 1
            
            
            
    else:
        count += 1
print(count)

Solution (Python):

class UnionFind:
    def __init__(self, n):
        
        
        self.table = [-1] * n
 
    def _root(self, x):
        if self.table[x] < 0:
            return x
        else:
            
            self.table[x] = self._root(self.table[x])
            return self.table[x]
 
    def find(self, x, y):
        return self._root(x) == self._root(y)
 
    def union(self, x, y):
        r1 = self._root(x)
        r2 = self._root(y)
        if r1 == r2:
            return
        
        d1 = self.table[r1]
        d2 = self.table[r2]
        if d1 <= d2:
            self.table[r2] = r1
            if d1 == d2:
                self.table[r1] -= 1
        else:
            self.table[r1] = r2
 
 
if __name__ == '__main__':
    ans = 0
    n,m = map(int,input().split())
    s = list(map(int,input().split()))
    uf = UnionFind(n+1)
    for i in range(m):
        a,b = map(int,input().split())
        uf.union(a-1,b-1)
    for i in range(n):
        if uf.find(s[i]-1,i):
            ans += 1
        elif s[i]-1  == i :
            ans += 1
print(ans)

Solution (Python):
n,m = [int(x) for x in input().strip().split()]
par = list(range(n))
rank = [0]*n

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

def unite(x,y):
  x,y = map(find, (x,y))
  if x==y:
    return
  if rank[x]<rank[y]:
    par[x] = y
  else:
    par[y] = x
    if rank[x]==rank[y]:
      rank[x]+=1

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

p = [int(x) for x in input().strip().split()]
for _ in range(m):
  x,y = [int(z)-1 for z in input().strip().split()]
  unite(x,y)

p = sorted([(z,i) for i,z in enumerate(p)], reverse=True)
print(sum([same(val-1,idx) for val,idx in p]))

Solution (Python):
import collections
n,m = map(int,input().split())
p = list(map(int,input().split()))
base = 0
basemap = []
for i in range(n):
	if (i+1) == p[i]:
		base += 1
		basemap.append(i+1)

branch = dict()
for i in range(1,n+1):
	branch[i] = []

for i in range(m):
	x,y = map(int,input().split())
	branch[x].append(y)
	branch[y].append(x)
compare = [0 for i in range(n+1)]
for i in range(1,n+1):
	if branch[i] != []:
		compare[i] = 1

arrival = [0 for i in range(n+1)]
ans = []
q = []

ind = 1
while arrival != compare:
	counter = base
	while not(arrival[ind] == 0 and compare[ind] == 1):
		ind += 1
	q.append(ind)
	arrival[ind] = 1
	section = [q[0]]
	while len(q) > 0:
		next = branch[q[0]]
		for i in range(len(next)):
			if arrival[next[i]] == 0:
				section.append(next[i])
				arrival[next[i]] = 1
				q.append(next[i])
		q.pop(0)
	psec = []
	for i in range(len(section)):
		psec.append(p[section[i]-1])
	t = section + psec + basemap
	search = collections.Counter(t)
	for i in search:
		if search[i] == 2:
			 counter += 1
	ans.append(counter)
print(max(ans))

Solution (Python):
def main():
    n, m = map(int, input().split())
    p = map(int, input().split())
    trans = []

    for _ in range(m):
        x, y = map(int, input().split())
        trans.append((x, y))
    
    ss = dict()

    for t in trans:
        x, y = t
        xs = ss.get(x, None)
        ys = ss.get(y, None)

        if xs is None and ys is None:
            zs = set([x, y])
            ss[x] = zs
            ss[y] = zs
        elif xs is not None and ys is None:
            xs.add(y)
            ss[y] = xs
        elif xs is None and ys is not None:
            ys.add(x)
            ss[x] = ys
        else:
            if id(xs) == id(ys):
                continue

            if len(xs) >= len(ys):
                for yy in ys:
                    ss[yy] = xs
                    xs.add(yy)
            else:
                for xx in xs:
                    ss[xx] = ys
                    ys.add(xx)

    c = 0
    for i, v in enumerate(p, 1):
        if i == v:
            c += 1
        elif i in ss and v in ss[i]:
            c += 1
    print(c)

main()

Solution (Python):
N, M = map(int, input().split())
p = list(map(lambda x: int(x) -1 , input().split()))
class UnionFind:
    def __init__(self, n):
        self.data = [-1] * n
    def union(self, x, y):
        x,y = self.root(x), self.root(y)
        if x != y :
            if self.data[y] < self.data[x]:
                x,y = y,x
            self.data[x] += self.data[y]
            self.data[y] = x
        return x != y
    def root(self, x):
        if self.data[x] < 0 :
            return x
        self.data[x] = self.root(self.data[x])
        return self.data[x]
    def findSet(self, x, y):
        return self.root(x) == self.root(y)
uf = UnionFind(N)
for _ in range(M):
    px,py = map(int, input().split())
    px -= 1
    py -= 1
    uf.union(px,py)
ans = 0
for i, v in enumerate(p):
    ans += 1 if uf.findSet(v,i) else 0
print(ans)

Solution (Python):
N, M = map(int, input().split())
P = list(map(int, input().split()))
P = list(enumerate(P, start=1))


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

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


uf = UnionFind(N)
for m in range(M):
    x, y = map(int, input().split())
    uf.union(x, y)

ans = 0
for now, value in P:
    if uf.same_check(now, value):
        ans += 1
print(ans)