#include <bits/stdc++.h>
#define f(a, n) for (int a = 0; a < n; a++)
#define F(a, n) for (int a = 1; a <= n; a++)
using namespace std;

struct Student{
	map<int, int> mp;
	int sz = 1;
	Student* par = this;
}; 

Student* find(Student* a){
	if (a->par == a) return a;
	return a->par = find(a->par);
}

void join(Student* a, Student* b){ // b joins a
	a->sz += b->sz;
	b->par = a;
	for (auto p: b->mp){
		int x = p.first, y = p.second;
		a->mp[x] += y;
	}
}

int main(){
	int n, q;
	cin >> n >> q;
	Student A[200005];
	F(i, n) {
		int x;
		cin>>x;
		A[i].mp[x]++;
	}
	F(asdf, q){
		int a, b, c;
		cin >> a >> b >> c;
		if (a == 1){
			auto d = find(&A[b]);
			auto e = find(&A[c]);
			if (d != e){
				if (d->sz >= e->sz){
					join(d, e);
				} else{
					join(e, d);
				}
			}
		} else{
			cout<<find(&A[b])->mp[c]<<endl;
		}
	}
}
#include <bits/stdc++.h>

#define DEBUG(C) cerr << #C << " = " << C << endl;

using namespace std;
const int MOD = 1e9 + 7;

// UnionFind,素集合データ構造,DisjointSet

template<typename weight_type = int>
class union_find {
    static_assert(
            std::is_arithmetic<weight_type>::value,
            "Invalid weight type");
private:
    const std::function<void(int, int)> noop = [](int aa, int bb){};

    std::vector<int> uni;
    std::vector<int> edge_count_;
    std::vector<weight_type> weights;
    int size_;
    const void check(const int n) const {
        if (this->group_size() < 0) {
            assert(false);
        }
        if (!(0 <= n && n < this->all_size())) {
            assert(false);
        }
    }
public:
    union_find() : uni(0), edge_count_(0), weights(0), size_(-1) {}
    union_find(const int n)
            : uni(n, -1), edge_count_(n), weights(n), size_(n) {
        this->check(n - 1);
    }
    union_find(const std::vector<weight_type> &_weights)
            : uni(_weights.size(), -1), edge_count_(_weights.size()),
              weights(_weights), size_(_weights.size()) {
        this->check((int)_weights.size() - 1);
    }
    bool same(const int a, const int b) {
        this->check(a);
        this->check(b);
        return this->find(a) == this->find(b);
    }
    int find(const int a) {
        this->check(a);
        return this->uni[a] < 0 ?
               a :
                this->uni[a] = this->find(this->uni[a]);
    }
    bool unite(int a, int b) {
        return unite(a, b, noop);
    }
    bool unite(int a, int b, const std::function<void(int, int)> &f) {
        a = this->find(a);
        b = this->find(b);
        this->edge_count_[a]++;
        if (a == b) {
            return false;
        }
        this->size_--;
        if (this->uni[a] > this->uni[b]) {
            std::swap(a, b);
        }
        f(a, b);
        this->uni[a] += this->uni[b];
        this->weights[a] += this->weights[b];
        this->edge_count_[a] += this->edge_count_[b];
        this->uni[b] = a;
        return true;
    }
    const int group_size() const {
        return this->size_;
    }
    const int all_size() const {
        return this->uni.size();
    }
    const int size(const int a) {
        this->check(a);
        return -this->uni[this->find(a)];
    }
    const int edge_count(const int a) {
        this->check(a);
        return this->edge_count_[this->find(a)];
    }
    const weight_type weight(const int a) {
        this->check(a);
        return this->weights[this->find(a)];
    }
};

const int MAX = 2e5 + 10;
int N, Q;
int C[MAX];
map<int, map<int, int>> mp;

void solve() {
    cin >> N >> Q;
    union_find<> uf(N);
    for (int i = 0; i < N; ++i) {
        cin >> C[i];
        C[i]--;
        mp[i][C[i]] = 1;
    }

    for (int i = 0; i < Q; i++) {
        int mode;
        cin >> mode;
        if (mode == 1) {
            int a, b;
            cin >> a >> b;
            a--;
            b--;

            uf.unite(a, b, [&](int nxt_par, int bye) {
                for (auto [k, v] : mp[bye]) {
                    mp[nxt_par][k] += v;
                }
                mp.erase(bye);
            });

        } else {
            int x, y;
            cin >> x >> y;
            x--;
            y--;
            x = uf.find(x);
            const auto ans = mp[x].count(y) ? mp[x][y] : 0;
            cout << ans << endl;
        }
    }
}

int main(void) {
#ifndef ONLINE_JUDGE
    const auto in_stream = freopen("../in.txt", "r", stdin);
    if (in_stream == nullptr) {
        cerr << "ERROR!" << endl;
        return 1;
    }
#endif

    solve();

#ifndef ONLINE_JUDGE
    fclose(in_stream);
#endif
}
