#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <utility>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <limits>
#define rep(i,n) for(int i = 0; i < n; ++i)
#define rep1(i,n) for(int i = 1; i <= n; ++i)
using namespace std;
template<class T>bool chmax(T &a, const T &b) { if(a < b){ a = b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if(a > b){ a = b; return 1; } return 0; }
template<class T> inline int  sz(T &a) { return a.size(); }
using ll = long long; using ld = long double;
using pi = pair<int,int>; using pl = pair<ll,ll>;
using vi = vector<int>; using vvi = vector<vi>;
using vl = vector<ll>; using vvl = vector<vl>;
const int inf = numeric_limits<int>::max();
const ll infll = numeric_limits<ll>::max();
struct UFT{
  vector<int> par;//親
  vector<int> rank;//木の深さ
  vector<int> size;//木の大きさ
  int n;
  
  UFT(int _n)
  {
    n = _n;
    par.resize(n);
    rank.assign(n,0);
    size.assign(n,1);
    rep(i,n){
      par[i] = i;
    }
  }
  
  //xの根を返す
  int find(int x)
  {
    if(par[x] == x) return x;
    else return par[x] = find(par[x]);
  }

  //x,yを併合
  void unite(int x,int y)
  {
    x = find(x);
    y = find(y);
    if(x == y) return;

    if(size[x] < size[y]){
      par[x] = y;
      size[y] += size[x];
    }
    else{
      par[y] = x;
      size[x] += size[y];
      if(rank[x] == rank[y]) rank[x]++;
    }
  }

  //x,yが同じグループにいるかどうかを返す
  bool same(int x,int y)
  {
    return find(x) == find(y);
  }

  //xの属する木のサイズを探す
  int usize(int x)
  {
    return size[find(x)];
  }
};


int main()
{
  int n,q; cin >> n >> q;
  vi c(n);
  rep(i,n) cin >> c[i];
  UFT uf(n);
  vector<map<int,int>> mp(n);
  rep(i,n) {
    mp[i][c[i]]++;
  }
  rep(i,q) {
    int t,x,y; cin >> t >> x >> y;
    if(t == 1) {
      x--; y--;
      int a = uf.find(x), b = uf.find(y);
      uf.unite(x, y);
      if(b != uf.find(b)) {
	for(auto val: mp[b]) {
	  auto [id, num] = val;
	  mp[a][id] += num;
	}
      }
      if(a != uf.find(a)) {      
	for(auto val: mp[a]) {
	  auto [id, num] = val;
	  mp[b][id] += num;
	}
      }
    }
    else {
      x--;
      cout << mp[uf.find(x)][y] << "\n";
    }
  }
  
  return 0;
}

#include <cstdio>
#include <vector>
inline int min(int a,int b){return a<b?a:b;}
inline int max(int a,int b){return a>b?a:b;}
const int maxn = 8e5+5;
int n,q,c[maxn];
int head[maxn],tot;
struct Edge{
	int next,to;
}e[maxn];
inline void add_edge(int x,int y){
	e[++tot].next = head[x];
	e[tot].to = y,head[x] = tot;
}
int ANS[maxn];
int ans[maxn],siz[maxn],son[maxn],in[maxn],out[maxn],id[maxn],tim;
inline void dfs1(int u){
	siz[u] = (u <= n);
	if(u <= n)in[u] = out[u] = ++tim,id[tim] = u;
	if(u > n){
		in[u] = n+1,out[u] = 0;
		for(int i=head[u],v;v=e[i].to,i;i=e[i].next){
			dfs1(v);
//			printf("dfs:%d %d\n",u,v);
			siz[u] += siz[v];
			if(siz[v] > siz[son[u]])son[u] = v;
			in[u] = min(in[u],in[v]);
			out[u] = max(out[u],out[v]);
		}
	}
}
struct Query{int id,col;};
std :: vector <Query> qu[maxn];
inline void dfs2(int u){
	if(u <= n)++ans[c[u]];
	else{
		for(int i=head[u],v;v=e[i].to,i;i=e[i].next){
			if(v != son[u]){
	//			printf("vark :%d %d\n",u,ans[2]);
	//			printf("inertval : %d %d %d\n",v,in[v],out[v]);
				dfs2(v);
				
				for(int j=in[v];j<=out[v];++j)ans[c[id[j]]]--;
			}
		}
		dfs2(son[u]);
	//	printf("vark :%d %d\n",u,ans[2]);
		for(int i=head[u],v;v=e[i].to,i;i=e[i].next)
			if(v != son[u])
				for(int j=in[v];j<=out[v];++j)ans[c[id[j]]]++;
	}
	for(int i=0;i<qu[u].size();++i)ANS[qu[u][i].id] = ans[qu[u][i].col];
}
int fa[maxn<<1];
inline int getfa(int x){return fa[x] == x ? x : fa[x] = getfa(fa[x]);}
int nodcnt,ccnt;
int main(){
	scanf("%d %d",&n,&q);
	for(int i=1;i<=n;++i)scanf("%d",&c[i]);
	for(int i=1;i<=n*2;++i)fa[i] = i;
	nodcnt = n;
	for(int i=1;i<=q;++i){
		int ty,a,b;
		scanf("%d %d %d",&ty,&a,&b);
		a = getfa(a);
		if(ty == 1)b = getfa(b);
		if(ty == 1){
			if(a != b)
				add_edge(++nodcnt,a),add_edge(nodcnt,b),fa[a] = nodcnt,fa[b] = nodcnt;
		}
		else qu[a].push_back((Query){++ccnt,b});
	}
	for(int i=1;i<=2*n;++i)if(i == getfa(i))dfs1(i);
	for(int i=1;i<=2*n;++i)
		if(i == getfa(i)){
			dfs2(i);
			for(int j=in[i];j<=out[i];++j)--ans[c[id[j]]];
		}
//	for(int i=1;i<=2*n;++i)printf("%d %d\n",in[i],out[i]);
//	puts("");
//	for(int i=1;i<=2*n;++i){
//		for(int j=0;j<qu[i].size();++j)printf("%d %d\n",qu[i][j].col,qu[i][j].id);
//		puts("end1");
//	}
//	puts("");
	for(int i=1;i<=ccnt;++i)printf("%d\n",ANS[i]);
	return 0;
}
/*
5 5
2 2 2 2 2
1 1 2
1 1 3
1 2 3
2 2 2
2 4 2
*/