#include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<(n);i++)
#define N 200005
#define INF 1000000005
#define INFLL 2e18
#define PI 3.1415926535897
typedef long long ll;
#define ALL(v) (v).begin(),(v).end()
#define SZ(x) int(x.size())
#define IN(a) cin>>(a)
#define OUT(a) cout<<(a)<<endl
typedef pair<int,int> P;
const int MAX = (1<<20);
const int MOD = 1000000007;

int par[MAX];
int depth[MAX];
int siz[MAX];
bool check[MAX];
//初期化
void init(){
    for(int i=0;i<MAX;i++){
        par[i]=i;
        siz[i]=1;
        check[i]=true;
    }
}
//根を探索　
int root(int x){
    if(par[x]==x){
        return x;
    }else{
        return par[x]=root(par[x]);
    }
}
 
//統合
void unit(int x,int y){
    x=root(x);
    y=root(y);
    if(x==y){
        check[x]=false;
        return;
    }
    if(depth[x]>depth[y])swap(x,y);
    par[x]=y;
    siz[y]+=siz[x];
    check[y]&=check[x];
    if(depth[x]==depth[y])depth[x]++;
}
// 同じ集合か判定
bool issame(int x,int y){
    return root(x)==root(y);
}
 
//集合の大きさ
int size(int x){
    return siz[root(x)];
}
void solve(){
    int n;
    cin>>n;
    map<int,int>mp,cnt;
    init();
    vector<int>a(n),b(n);
    REP(i,n){
        cin>>a[i]>>b[i];
        a[i]--;b[i]--;
        unit(a[i],b[i]);
    }
    REP(i,n){
        if(0==cnt[a[i]]++)mp[root(a[i])]++;
        if(0==cnt[b[i]]++)mp[root(b[i])]++;
    }
    int ans=0;
    for(auto p:mp){
        ans+=p.second;
        if(check[p.first])ans--;
    }
    OUT(ans);
}



int main(){
    solve();
    return 0;
}

#include "bits/stdc++.h"
using namespace std;
typedef int ll;
typedef pair<ll ,ll> pll;
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define all(X) (X).begin(), (X).end()
#define REP(i,x,y) for(ll i = x;i <= y;++i)
#define fastio ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0)
vector<string> vec_splitter(string s) {
    for(char& c: s) c = c == ','?  ' ': c;
    stringstream ss; ss << s;
    vector<string> res;
    for(string z; ss >> z; res.push_back(z))
        ;
    return res;
}
void debug_out(vector<string> args, int idx) { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(vector<string> args, int idx, Head H, Tail... T) {
    if(idx > 0) cerr << ", ";
    stringstream ss; ss << H;
    cerr << args[idx] << " = " << ss.str();
    debug_out(args, idx + 1, T...);
}
#define debug(...) debug_out(vec_splitter(#__VA_ARGS__), 0, __VA_ARGS__)
void localTest() {
    #ifndef ONLINE_JUDGE
        freopen("inp", "r", stdin);
        freopen("out", "w", stdout);
    #endif      
}
const ll N = 2e5 + 5;
ll par[N], sz[N];
unordered_map<ll, ll> has[N];
ll find(ll x) {
	if(x == par[x]) {
		return x;
	}
	return par[x] = find(par[x]);
}
void merge(ll x, ll y) {
	ll rx = find(x), ry = find(y);
	if(rx == ry) {
		return;
	}
	if(sz[rx] < sz[ry]) {
		swap(rx, ry);
	}
	par[ry] = rx;
	sz[rx] += sz[ry];
	for(auto u : has[ry]) {
		has[rx][u.F] += u.S;
	}
	return;
}
int main() {

    localTest();
    fastio;
    ll n, q;
    cin >> n >> q;
    for(ll i = 1; i <= n; ++i) {
    	ll x;
    	par[i] = i;
    	cin >> x;
    	sz[x] = 1;
    	has[i][x]++;
    }
    while(q--) {
    	ll ty, x, y;
    	cin >> ty >> x >> y;
    	if(ty == 1) {
    		merge(x, y);
    	} else {
    		ll rx = find(x);
    		cout << has[rx][y] << "\n";
    	}
    }

    return 0;
}