# https://atcoder.jp/contests/arc097/tasks/arc097_b

# Pについてp_xとp_yでuniteしていくと、スワップできる集合が獲得できる

# 1,2,3...i...Nにできるかだが, iについてp_iとiがスワップできるかはunion-findで探せばよい





import sys

read = sys.stdin.readline





def read_ints():

    return list(map(int, read().split()))





def read_tuple(H):

    '''

    H is number of rows

    '''

    ret = []

    for _ in range(H):

        ret.append(tuple(map(int, read().split())))

    return ret





class UnionFind:

    def __init__(self, N):

        self.N = N  # ノード数

        # 親ノードをしめす。負は自身が親ということ。

        self.parent = [-1] * N  # idxが各ノードに対応。



    def root(self, A):

        # print(A)

        # ノード番号を受け取って一番上の親ノードの番号を帰す

        if (self.parent[A] < 0):

            return A

        self.parent[A] = self.root(self.parent[A])  # 経由したノードすべての親を上書き

        return self.parent[A]



    def size(self, A):

        # ノード番号を受け取って、そのノードが含まれている集合のサイズを返す。

        return -self.parent[self.root(A)]



    def unite(self, A, B):

        # ノード番号を2つ受け取って、そのノード同士をつなげる処理を行う。

        # 引数のノードを直接つなぐ代わりに、親同士を連結する処理にする。

        A = self.root(A)

        B = self.root(B)



        # すでにくっついている場合

        if (A == B):

            return False



        # 大きい方に小さい方をくっつけたほうが処理が軽いので大小比較

        if (self.size(A) < self.size(B)):

            A, B = B, A



        # くっつける

        self.parent[A] += self.parent[B]  # sizeの更新

        self.parent[B] = A  # self.rootが呼び出されればBにくっついてるノードもすべて親がAだと上書きされる



        return True



    def is_in_same(self, A, B):

        return self.root(A) == self.root(B)





# default import

from collections import defaultdict, Counter, deque

from operator import itemgetter

from itertools import product, permutations, combinations

from bisect import bisect_left, bisect_right  # , insort_left, insort_right





N, M = read_ints()

P = [p - 1 for p in read_ints()]

uf = UnionFind(N)

for _ in range(M):

    x, y = read_ints()

    uf.unite(P[x - 1], P[y - 1])



ans = 0

for i in range(N):

    ans += uf.is_in_same(i, P[i])



print(ans)

# https://atcoder.jp/contests/arc097/tasks/arc097_b

# Pについてp_xとp_yでuniteしていくと、スワップできる集合が獲得できる

# 1,2,3...i...Nにできるかだが, iについてp_iとiがスワップできるかはunion-findで探せばよい





import sys

read = sys.stdin.readline





def read_ints():

    return list(map(int, read().split()))





def read_tuple(H):

    '''

    H is number of rows

    '''

    ret = []

    for _ in range(H):

        ret.append(tuple(map(int, read().split())))

    return ret





class UnionFind:

    def __init__(self, N):

        self.N = N  # ノード数

        # 親ノードをしめす。負は自身が親ということ。

        self.parent = [-1] * N  # idxが各ノードに対応。



    def root(self, A):

        # print(A)

        # ノード番号を受け取って一番上の親ノードの番号を帰す

        if (self.parent[A] < 0):

            return A

        self.parent[A] = self.root(self.parent[A])  # 経由したノードすべての親を上書き

        return self.parent[A]



    def size(self, A):

        # ノード番号を受け取って、そのノードが含まれている集合のサイズを返す。

        return -self.parent[self.root(A)]



    def unite(self, A, B):

        # ノード番号を2つ受け取って、そのノード同士をつなげる処理を行う。

        # 引数のノードを直接つなぐ代わりに、親同士を連結する処理にする。

        A = self.root(A)

        B = self.root(B)



        # すでにくっついている場合

        if (A == B):

            return False



        # 大きい方に小さい方をくっつけたほうが処理が軽いので大小比較

        if (self.size(A) < self.size(B)):

            A, B = B, A



        # くっつける

        self.parent[A] += self.parent[B]  # sizeの更新

        self.parent[B] = A  # self.rootが呼び出されればBにくっついてるノードもすべて親がAだと上書きされる



        return True



    def is_in_same(self, A, B):

        return self.root(A) == self.root(B)





# default import



N, M = read_ints()

P = [p - 1 for p in read_ints()]

uf = UnionFind(N)

for _ in range(M):

    x, y = read_ints()

    uf.unite(P[x - 1], P[y - 1])



ans = 0

for i in range(N):

    ans += uf.is_in_same(i, P[i])



print(ans)

# https://atcoder.jp/contests/arc097/tasks/arc097_b
# Pについてp_xとp_yでuniteしていくと、スワップできる集合が獲得できる
# 1,2,3...i...Nにできるかだが, iについてp_iとiがスワップできるかはunion-findで探せばよい
import sys

read = sys.stdin.readline


def read_ints():
    return list(map(int, read().split()))


def read_tuple(H):
    """
    H is number of rows
    """
    ret = []
    for _ in range(H):
        ret.append(tuple(map(int, read().split())))
    return ret


class UnionFind:
    def __init__(self, N):
        self.N = N  # ノード数
        # 親ノードをしめす。負は自身が親ということ。
        self.parent = [-1] * N  # idxが各ノードに対応。

    def root(self, A):
        # print(A)
        # ノード番号を受け取って一番上の親ノードの番号を帰す
        if self.parent[A] < 0:
            return A
        self.parent[A] = self.root(self.parent[A])  # 経由したノードすべての親を上書き
        return self.parent[A]

    def size(self, A):
        # ノード番号を受け取って、そのノードが含まれている集合のサイズを返す。
        return -self.parent[self.root(A)]

    def unite(self, A, B):
        # ノード番号を2つ受け取って、そのノード同士をつなげる処理を行う。
        # 引数のノードを直接つなぐ代わりに、親同士を連結する処理にする。
        A = self.root(A)
        B = self.root(B)
        # すでにくっついている場合
        if A == B:
            return False
        # 大きい方に小さい方をくっつけたほうが処理が軽いので大小比較
        if self.size(A) < self.size(B):
            A, B = B, A
        # くっつける
        self.parent[A] += self.parent[B]  # sizeの更新
        self.parent[B] = A  # self.rootが呼び出されればBにくっついてるノードもすべて親がAだと上書きされる
        return True

    def is_in_same(self, A, B):
        return self.root(A) == self.root(B)


# default import
from collections import defaultdict, Counter, deque
from operator import itemgetter
from itertools import product, permutations, combinations
from bisect import bisect_left, bisect_right  # , insort_left, insort_right

N, M = read_ints()
P = [p - 1 for p in read_ints()]
uf = UnionFind(N)
for _ in range(M):
    x, y = read_ints()
    uf.unite(P[x - 1], P[y - 1])
ans = 0
for i in range(N):
    ans += uf.is_in_same(i, P[i])
print(ans)

# https://atcoder.jp/contests/arc097/tasks/arc097_b
# Pについてp_xとp_yでuniteしていくと、スワップできる集合が獲得できる
# 1,2,3...i...Nにできるかだが, iについてp_iとiがスワップできるかはunion-findで探せばよい
import sys

read = sys.stdin.readline


def read_ints():
    return list(map(int, read().split()))


def read_tuple(H):
    """
    H is number of rows
    """
    ret = []
    for _ in range(H):
        ret.append(tuple(map(int, read().split())))
    return ret


class UnionFind:
    def __init__(self, N):
        self.N = N  # ノード数
        # 親ノードをしめす。負は自身が親ということ。
        self.parent = [-1] * N  # idxが各ノードに対応。

    def root(self, A):
        # print(A)
        # ノード番号を受け取って一番上の親ノードの番号を帰す
        if self.parent[A] < 0:
            return A
        self.parent[A] = self.root(self.parent[A])  # 経由したノードすべての親を上書き
        return self.parent[A]

    def size(self, A):
        # ノード番号を受け取って、そのノードが含まれている集合のサイズを返す。
        return -self.parent[self.root(A)]

    def unite(self, A, B):
        # ノード番号を2つ受け取って、そのノード同士をつなげる処理を行う。
        # 引数のノードを直接つなぐ代わりに、親同士を連結する処理にする。
        A = self.root(A)
        B = self.root(B)
        # すでにくっついている場合
        if A == B:
            return False
        # 大きい方に小さい方をくっつけたほうが処理が軽いので大小比較
        if self.size(A) < self.size(B):
            A, B = B, A
        # くっつける
        self.parent[A] += self.parent[B]  # sizeの更新
        self.parent[B] = A  # self.rootが呼び出されればBにくっついてるノードもすべて親がAだと上書きされる
        return True

    def is_in_same(self, A, B):
        return self.root(A) == self.root(B)


# default import
N, M = read_ints()
P = [p - 1 for p in read_ints()]
uf = UnionFind(N)
for _ in range(M):
    x, y = read_ints()
    uf.unite(P[x - 1], P[y - 1])
ans = 0
for i in range(N):
    ans += uf.is_in_same(i, P[i])
print(ans)

-from collections import defaultdict, Counter, deque -from operator import itemgetter -from itertools import product, permutations, combinations -from bisect import bisect_left, bisect_right  # , insort_left, insort_right -