#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const ll INF = 1LL<<60;

ll gcd(ll a, ll b) {
  if(b == 0) return a;
  return gcd(b, a % b);
}

template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }

// union by size + path having
class UnionFind {
public:
    vector <ll> par; // 各元の親を表す配列
    vector <ll> siz; // 素集合のサイズを表す配列(1 で初期化)

    // Constructor
    UnionFind(ll sz_): par(sz_), siz(sz_, 1LL) {
        for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
    }
    void init(ll sz_) {
        par.resize(sz_);
        siz.assign(sz_, 1LL);  // resize だとなぜか初期化されなかった
        for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
    }

    // Member Function
    // Find
    ll root(ll x) { // 根の検索
        while (par[x] != x) {
            x = par[x] = par[par[x]]; // x の親の親を x の親とする
        }
        return x;
    }

    // Union(Unite, Merge)
    bool merge(ll x, ll y) {
        x = root(x);
        y = root(y);
        if (x == y) return false;
        // merge technique（データ構造をマージするテク．小を大にくっつける）
        if (siz[x] < siz[y]) swap(x, y);
        siz[x] += siz[y];
        par[y] = x;
        return true;
    }

    bool issame(ll x, ll y) { // 連結判定
        return root(x) == root(y);
    }

    ll size(ll x) { // 素集合のサイズ
        return siz[root(x)];
    }
};

// 重複の無いvectorの共通部分を返す
// set_intersectionでもいけるらしいがせっかくなので実装
ll intersec_vector(vector<ll> va, vector<ll> vb){

    sort(va.begin(), va.end());
    sort(vb.begin(), vb.end());

    ll ans = 0;

    auto itra = va.begin();
    auto itrb = vb.begin();
    
    while(1){
        if(*itra == *itrb){
            ans++;
            itra++;
            itrb++;
        }else if(*itra > *itrb){
            itrb++;
        }else{
            itra++;
        }
        if(itra == va.end() || itrb == vb.end()) break;

    }
    return ans;
}


int main(){
    cin.tie(0);
   	ios::sync_with_stdio(false);

    
    ll N, M;
    cin >> N >> M;
    vector<ll> p(N);

    ll tmp_p = 0;
    for(ll i = 0; i < N; i++){
        cin >> tmp_p;
        tmp_p--;//0-indexed
        p[i] = tmp_p;
    }

    UnionFind uf(N);

    ll tmp_x, tmp_y;
    for(ll i = 0; i < M; i++){
        cin >> tmp_x >> tmp_y;
        tmp_x--;
        tmp_y--;//0_indexedに
        uf.merge(tmp_x, tmp_y);
    }

    ll tmp_root;
    map<ll, pair<vector<ll>, vector<ll>>> mp;
    for(ll i = 0; i < N; i++){
        tmp_root = uf.root(i); //iの親
        if(mp.count(tmp_root) == 0){//親(自身含む)がmapのキーになかったら
            vector<ll> tv1;
            vector<ll> tv2;
            mp[tmp_root] = make_pair(tv1, tv2); //pairを作って代入
            mp[tmp_root].first.push_back(i);//indexのベクタ(重複無し)
            mp[tmp_root].second.push_back(p[i]);//p[i]の値のベクタ(重複無し)
        }else{//親(自身含む)がmapのキーにあったら
            mp[tmp_root].first.push_back(i);
            mp[tmp_root].second.push_back(p[i]);
        }
    }

    // //mapを
    // for(auto itr = mp.begin(); itr != mp.end(); itr++){
    //     for(auto itrv = itr->second.second.begin(); itrv != itr->second.second.end(); itrv++){
    //         cout << *itrv << endl;
    //     }
    // }

    ll ans = 0;
    for(auto itr = mp.begin(); itr != mp.end(); itr++){
        // indexのvector
        ans += intersec_vector(itr->second.first, itr->second.second);
    }

    cout << ans << endl;

    return 0;
}



Measured memory_bytes: 18304