#pragma GCC optimize("Ofast")

#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pop_b pop_back
#define pf push_front
#define pop_f pop_front
#define mt make_tuple
#define eb emplace_back
#define sf(x) sizeof(x)
#define len(x) x.length()
#define sz(x) x.size()
#define fastio() ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)

#define LB(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())
#define UB(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())
typedef long long ll;
typedef pair<ll,ll> ii;
typedef long double ld; 
typedef vector<int> vi;
typedef vector<set<ll>> vset;
typedef vector<ll> vl;
typedef vector<ld> vd;
typedef deque<ll> dql;
typedef deque<int> dqi;
typedef unsigned long long ull;
typedef tuple<int,int,int> State;

#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
	cerr << *it << " = " << a << "\n";
	err(++it, args...);
}

#define vmax(type)   std::numeric_limits<type>::max()
#define vmin(type)   std::numeric_limits<type>::min()
#define each(a,x) for( auto &a:(x))
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define repr(i, n) for (ll i = (n) - 1; i >= 0; i--)
#define rep2(i, l, r) for (ll i = (l); i < (r); i++)
#define rep2r(i, l, r) for (ll i = (r) - 1; i >= (l); i--)
#define range(a) a.begin(), a.end()
#define deb(x) cout<<#x<<" "<<x<<endl;
#define cinai(a, n) vi a(n); rep(i, n) { cin>>a[i]; }
#define cinal(a, n) vl a(n); rep(i, n) { cin>>a[i]; }
#define coutai(a, n) rep(i, n) { cout<<a[i]<<" "; } ent;
#define coutal(a, n) rep(i, n) { cout<<a[i]<<" "; } ent;
#define ent cout<<endl;
#define resize_vec(a) a.resize(unique(a.begin(), a.end()) - a.begin());
#define ms(dp, x) memset(dp, x, sf(dp))
#define endl '\n'

ll powm(ll a, ll b, ll mod) {
	ll res=1;
	while(b) {
		if(b&1)
			res=(res*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return res;
}

int db = 0;
const ll mod = 1e9 + 7;
const ll N = 1000005;
const ll inf = 1e9;
#define er if(db) error

class DisjointSet{ 
public:
    vector<int> parent;
    vector<map<int, int>> pres;
    DisjointSet(int n, vector<int> clas): parent(n) { 
    	for(int i=0; i<n; i++) 
    		parent[i] = i; 
    	pres.resize(n);
    	for(int i = 0; i < n; i++)
    		pres[i][clas[i]] = 1;
    }
    void join(int a, int b) { 
    	if(check(a, b))
    		return;
    	if(pres[find(a)].size() < pres[find(b)].size())
    		swap(a, b); 
    	int par_a = find(a);
    	for(auto it : pres[find(b)])
    		pres[par_a][it.fi] += it.se;
    	parent[find(b)] = find(a);
    }
    int find(int a){ 
    	return a == parent[a] ? a : parent[a] = find(parent[a]); 
    }
    bool check(int a, int b){ 
    	return find(a) == find(b); 
    }
};

void solve()
{
	int n, q;
	cin>>n>>q;
	cinai(c, n);
	DisjointSet dis(n, c);
	while(q--){
		int tc;
		cin>>tc;
		int a, b;
		cin>>a>>b;
		if(tc == 1){
			dis.join(a-1, b-1);
		}else{
			cout<<dis.pres[dis.find(a-1)][b]<<endl;	
		}
	}
}

// #define _DEBUG
// #define testCases
signed main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cout << fixed << setprecision(15);
	
	// freopen("input.txt", "r", stdin);
	// freopen("output.txt", "w", stdout);

	int tc = 1;
#ifdef testCases
	cin>>tc;
#endif
	for(int t = 1; t <= tc; t++)
	{
#ifdef _DEBUG
	db = 1;
	int tt = clock();
#endif
		// cout<<"Case #"<<t<<": ";
		solve();
		
#ifdef _DEBUG
		cerr << "TIME = " << clock() - tt << endl;
		tt = clock();
#endif
	}
	return 0;
}



#include <bits/stdc++.h>
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;
using ll=long long;
using Graph=vector<vector<int>>;
#define MAX 1000000
#define MOD 1000000007
#define INF 1000000000000000000

vector<map<int,int>> m;
vector<int> parent;
int find(int x){
  int y=parent[x];
  if(y!=parent[y]){
    y=find(y);
  }
  return parent[x]=y;
}
void unite(int a,int b){
  int x=find(a);
  int y=find(b);
  if(x!=y){
    if(m[x].size()>m[y].size()){
      parent[y]=x;
      for(auto p:m[y]){
        m[x][p.first]+=p.second;
      }
    }else{
      parent[x]=y;
      for(auto p:m[x]){
        m[y][p.first]+=p.second;
      }
    }
  }
}

int main(){
  int N,Q;
  cin>>N>>Q;
  vector<int> C(N);
  for(int i=0;i<N;i++){
    cin>>C[i];
    C[i]--;
  }
  parent.resize(N);
  m.resize(N);
  for(int i=0;i<N;i++){
    parent[i]=i;
    m[i][C[i]]++;
  }
  for(int i=0;i<Q;i++){
    int q,a,b;
    cin>>q>>a>>b;
    a--;b--;
    if(q==1){
      unite(a,b);
    }else{
      cout<<m[find(a)][b]<<endl;
    }
  }
}
