#include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define REP(i,n) for (int i = 1; i < (int)(n); i++)
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define debug(var) do{cout << #var << " : "; view(var);}while(0)
template<class T> bool chmin(T &a, T b) {if(a>b) {a=b;return 1;}return 0;}
template<class T> bool chmax(T &a, T b) {if(a<b) {a=b;return 1;}return 0;}
using namespace std;
template<class T> void view(T e) {cout << e << endl;}
template<class T> void view(const vector<T> &v) {for(const auto &e : v){cout << e << " ";} cout << endl;}
template<class T> void view(const vector<vector<T>> &vv) {for(const auto &v : vv){view(v);}}
using vint = vector<int>;
using vvint = vector<vector<int>>;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
using P = pair<int,int>;
const int inf = 1<<30;
const ll inf_l = 1LL<<61;
const int MAX = 1e5;

// union-find
struct union_find {
    vector<int> dat;

    union_find(int size) {dat.resize(size,-1);}

    int find(int x) {
        if (dat[x] < 0) {return x;}
        return dat[x] = find(dat[x]);
    }

    bool unite(int x, int y) {
        x = find(x); y = find(y);
        if (x == y) {return false;}
        if (dat[x] > dat[y]) swap(x,y);
        dat[x] += dat[y];
        dat[y] = x;
        return true;
    }

    int size(int x) {return -dat[find(x)];}
};

int main() {
    int n, q; cin >> n >> q;
    vector<unordered_map<int,int>> ct(n);
    rep(i,n) {
        int c; cin >> c;
        ct[i][c]++;
    }
    union_find uf(n);
    rep(i,q) {
        int query, a, b; cin >> query >> a >> b;
        if (query == 1) {
            a--; b--;
            a = uf.find(a);
            b = uf.find(b);
            if (uf.unite(a, b)) {
                int r = uf.find(a);
                for (P p : ct[a + b - r]) {
                    ct[r][p.first] += p.second;
                }
            }
        } else {
            a--;
            cout << ct[uf.find(a)][b] << endl;
        }
    }
}
#include<bits/stdc++.h>
using namespace std;
const int N=200000;
int c[N];
int Root[N],Rank[N],Size[N];
map<int,int>m[N];
int find(int x){
    if(Root[x]==x)return x;
    else return Root[x]=find(Root[x]);
}
void unite(int x,int y){
    int X=find(x);
    int Y=find(y);
    if(X==Y)return;
    if(Rank[X]<Rank[Y]){
        Root[X]=Y;
        for(pair<int,int>p:m[X])m[Y][p.first]+=p.second;
        m[X].clear();
    }
    else{
        Root[Y]=X;
        for(pair<int,int>p:m[Y])m[X][p.first]+=p.second;
        m[Y].clear();
        if(Rank[X]==Rank[Y])Rank[X]++;
    }
    return;
}
int main(){
    int n,q;
    cin>>n>>q;
    for(int i=0;i<n;i++){
        cin>>c[i];
        c[i]--;
        Root[i]=i;
        Rank[i]=0;
        m[i][c[i]]++;
    }
    vector<int>ans;
    for(int i=0;i<q;i++){
        int t,x,y;
        cin>>t>>x>>y;
        x--,y--;
        if(t==1)unite(x,y);
        if(t==2)ans.push_back(m[find(x)][y]);
    }
    for(int i:ans)cout<<i<<endl;
}