// Slower C++ solution:
#include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for(int i = 0; i < n; i++)

#define rep2(i, x, n) for(int i = x; i <= n; i++)

#define rep3(i, x, n) for(int i = x; i >= n; i--)

#define elif else if

#define sp setprecision

#define pb(x) push_back(x)

typedef long long ll;

typedef long double ld;

typedef pair<int, int> pii;

typedef pair<ll, ll> pll;

typedef pair<ld, ld> pdd;

const ll MOD = 1e9+7;

const ll MOD2 = 998244353;

const int inf = INT_MAX;

const ll INF = LLONG_MAX;

const string alpha = "abcdefghijklmnopqrstuvwxyz";



struct unionfind_tree{

    int par[500000], rank[500000], num[500000];

    //要素数n(0〜n-1)の初期化されたUnion-Find木を構築

    unionfind_tree(int N){

        rep(i, N){par[i] = i, rank[i] = 0, num[i] = 1;}

    }

    //ノードxの根を取得

    int find(int x){

        if(par[x] == x) return x;

        else return find(par[x]);

    }

    //xとyの属する集合を併合

    void unite(int x, int y){

        x = find(x), y = find(y);

        if(x == y) return;

        elif(rank[x] < rank[y]){par[x] = y, num[y] += num[x];}

        else{

            par[y] = x, num[x] += num[y];

            if(rank[x] == rank[y]) rank[x]++;

        }

    }

    //xの属する集合の要素数を取得

    int size(int x){

        return num[find(x)];

    }

    //xとyが同じ集合に属するか判定

    bool same(int x, int y){

        return find(x) == find(y);

    }

};



int main(){

    int N, M;

    cin >> N >> M;

    int q[N];

    rep(i, N){

        int p;

        cin >> p;

        p--;

        q[p] = i;

    }

    unionfind_tree uft(N);

    rep(i, M){

        int x, y;

        cin >> x >> y;

        x--, y--;

        uft.unite(x, y);

    }

    int ans = 0;

    rep(i, N){

        if(uft.same(i, q[i])) ans++;

    }

    cout << ans << endl;

}

// Faster C++ solution for the same problem (measured speedup: 1.1442106963428356x):
#include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for(int i = 0; i < n; i++)

#define rep2(i, x, n) for(int i = x; i <= n; i++)

#define rep3(i, x, n) for(int i = x; i >= n; i--)

#define elif else if

#define sp(x) fixed << setprecision(x)

#define pb push_back

#define eb emplace_back

#define all(x) x.begin(), x.end()

#define sz(x) (int)x.size()

using ll = long long;

using ld = long double;

using pii = pair<int, int>;

using pil = pair<int, ll>;

using pli = pair<ll, int>;

using pll = pair<ll, ll>;

const ll MOD = 1e9+7;

//const ll MOD = 998244353;

const int inf = (1<<30)-1;

const ll INF = (1LL<<60)-1;

const ld EPS = 1e-10;

template<typename T> bool chmax(T &x, const T &y) {return (x < y)? (x = y, true) : false;};

template<typename T> bool chmin(T &x, const T &y) {return (x > y)? (x = y, true) : false;};



struct Union_Find_Tree{

    vector<int> par, rank, num;

    

    Union_Find_Tree(int N){

        par.assign(N, -1);

        rank.assign(N, 0);

        num.assign(N, 1);

    }

    

    int root(int x){

        if(par[x] < 0 || par[x] == x) return x;

        return par[x] = root(par[x]);

    }

    

    void unite(int x, int y){

        x = root(x), y = root(y);

        if(x == y) return;

        elif(rank[x] < rank[y]) par[x] = y, num[y] += num[x];

        else{

            par[y] = x, num[x] += num[y];

            if(rank[x] == rank[y]) rank[x]++;

        }

    }

    

    int size(int x) {return num[root(x)];}

    

    bool same(int x, int y){

        return root(x) == root(y);

    }

    

    void clear(){

        fill(all(par), -1);

        fill(all(rank), 0);

        fill(all(num), 1);

    }

};



int main(){

    int N, M;

    cin >> N >> M;

    int p[N];

    rep(i, N) {cin >> p[i]; p[i]--;}

    Union_Find_Tree uf(N);

    rep(i, M){

        int u, v; cin >> u >> v; u--, v--;

        uf.unite(u, v);

    }

    int ans = 0;

    rep(i, N) ans += uf.same(i, p[i]);

    cout << ans << endl;

}