#include <algorithm>
#include <bitset>
#include <climits>
#include <cmath>
#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <list>
#include <deque>
#include <queue>
#include <iomanip>

using namespace std;

#define REP(i,n) for (decltype(n) i = 0; i < n; i++)

using ll = long long;
using ivec = vector<int>;
using lvec = vector<long>;
using ipair = pair<int, int>;
using llvec = vector<ll>;
using llpair = pair<ll, ll>;


template<typename T>
vector<T> read_args()
{
	T N;
	cin >> N;
	vector<T> v(N);
	for (auto& e : v) {
		cin >> e;
	}
	return v;
}

template<class T>
void sort(T& v)
{
	sort(v.begin(), v.end());
}

template<class T>
void rsort(T& v)
{
	sort(v.begin(), v.end(), greater<typename T::value_type>());
}

void answer(bool b)
{
	cout << (b ? "Yes" : "No") << endl;
}

typedef unordered_map<int, int> Cluster;
vector<Cluster*> clusters;
ivec c;

void merge2(Cluster& a, Cluster& b)
{
	for (auto&e : b) {
		if (a.find(e.first) != a.end()) {
			a[e.first] += e.second;
		} else {
			a[e.first] = e.second;
		}
	}
}

void dump(Cluster* cluster)
{
	return;
	for (auto &e : *cluster) {
		cout << "[" << e.first << "]" << e.second << endl;;
	}
}

class UnionFind {
public:
	UnionFind(int n)
	{
		parent.assign(n, 0);
		for (int i = 0; i < n; i++)
			parent[i] = i;
		rank.assign(n, 0);
	}

	bool unite(int a, int b)
	{
		a = root(a);
		b = root(b);
		if (a == b)
			return false;
		if (rank[a] > rank[b]) {
			parent[b] = a;
			merge(a, b);
		} else {
			parent[a] = b;
			merge(b, a);
			if (rank[a] == rank[b])
				rank[b]++;
		}
		return true;
	}

	void merge(int a, int b)
	{
		// cout << "merge " << a << "," << b << endl;
		if (!clusters[a]) {
			clusters[a] = new Cluster;
			(*clusters[a])[c[a]] = 1;
		}
		if (!clusters[b]) {
			clusters[b] = new Cluster;
			(*clusters[b])[c[b]] = 1;
		}
		merge2(*clusters[a], *clusters[b]);
		dump(clusters[a]);
		delete clusters[b];
		clusters[b] = nullptr;
	}

	bool same(int a, int b)	{ return root(a) == root(b); }
	bool isRoot(int a) { return parent[a] == a; }
	int root(int i) { return parent[i] == i ? i : parent[i] = root(parent[i]); }
private:
	std::vector<int> parent;
	std::vector<int> rank;
};

int main()
{
	int n,q;
	cin >> n >> q;

	UnionFind uf(n);

	c.assign(n, 0);
	REP(i,n) {
		int z;
		cin >> z;
		c[i] = z;
	}
	clusters.assign(n, 0);

	REP(z, q) {
		int p,x,y;
		cin >> p >> x >> y;
		// cout << p << "," << x << "," << y << endl;
		x--;
		if (p == 1) {
			y--;
			uf.unite(x,y);
		} else {
			// cout << x << "," << y << endl;
			x = uf.root(x);
			// cout << x << "," << x << endl;
			auto p = clusters[x];
			if (!p) {
				// cout << "no cluster" << endl;
				if (c[x] == y)
					cout << 1 << endl;
				else
					cout << 0 << endl;
			} else {
				dump(p);
				auto it = p->find(y);
				if (it == p->end()) {
					cout << 0 << endl;
				} else {
					cout << it->second << endl;
				}
			}
		}
	}
	return 0;
}

//To debug :  g++ -g file.cpp -o code
//to flush output : fflush(stdout) or cout.flush()
//cout<<setprecision(p)<<fixed<<var
//use 1LL<<i to for 64 bit shifting , (ll)2 because by default 2 is ll
//take care of precedence rule of operators 
//do not forget to change the sizes of arrays and value of contants and other things after debugging  
 
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,n) for(i=a;i<n;++i)
#define irep(i,n,a) for(i=n;i>a;--i)
#define mod 1000000007
#define pb push_back
#define big 9223372036854775807
#define big1 LONG_MAX
#define big2 ll_MAX
#define big3 1000000000
#define sma1 LONG_MIN
#define sma2 ll_MIN
#define sma3 -1000000000
#define mp make_pair
#define dub double
#define ivec vector<ll>
#define lvec vector<long long>
#define cvec vector<char>
#define svec vector<string>
#define mt make_tuple
#define MOD 998244353
#define ld long double
#define pi acos(-1.0)
 
#define SZ(x)  (ll)(x.size())
 
//comment the below if not required
 
/*
 
#define ss second.second
#define ff first.first
#define f first
#define s second
#define sf second.first
#define fs first.second
*/
 
#define IOS std::ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
 
//cout<<"Case #"<<c<<": "<<ans<<"\n" ;


const int N = 2e5+1;
int n,q,c,x,y,cl,Q,A,B;
vector<int> v[N];
map<int,int> m[N];
int a[N];

int main()
{

    int i,i1,j1;

    cin>>n>>q;

    for(i=1;i<=n;++i)
    {
        cin>>cl;
        v[i].pb(i);
        ++m[i][cl];
        a[i]=i;
    }

    for(i=1;i<=q;++i)
    {
        cin>>Q>>A>>B;

        if(Q==1)
        {
            i1=a[A],j1=a[B];

            if(i1==j1)
                continue;

            if(SZ(v[j1])>SZ(v[i1]))
                swap(i1,j1);

            //put j1 into i1

            for(auto u : v[j1])
            {
                a[u]=i1;
                v[i1].pb(u);
            }
            v[j1].clear();

            for(auto i = m[j1].begin();i!=m[j1].end();++i)
                m[i1][i->first]+=i->second;

            m[j1].clear();
        }
        else
        {
            cout<<m[a[A]][B]<<"\n";
        }

    }

    return 0;
}