#include <bits/stdc++.h>
#define INF 1e9
#define INFLL 1ull<<60u
using namespace std;

#define REPR(i,n) for(int i=(n); i >= 0; --i)
#define FOR(i, m, n) for(int i = (m); i < (n); ++i)
#define REP(i, n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define ALL(a)  (a).begin(),(a).end()
#define endl "\n"

template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
typedef long long ll;

using vi = vector<int>;
using vvi = vector<vi>;
using vpii = vector<pair<int,int>>;

class UnionFind {
public:
    vector <ll> par; // 各元の親を表す配列
    vector <map<int,int>> siz; // 素集合のサイズを表す配列(1 で初期化)

    // Constructor
    UnionFind(ll sz_): par(sz_), siz(sz_,map<int,int>()) {
        for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
    }

    void init(const vector<int>& classes) {
        REP(i,classes.size()) {
            siz[i][classes[i]] = 1;
        }
    }

    // Member Function
    // Find
    ll root(ll x) { // 根の検索
        while (par[x] != x) {
            x = par[x] = par[par[x]]; // x の親の親を x の親とする
        }
        return x;
    }

    // Union(Unite, Merge)
    bool merge(ll x, ll y) {
        x = root(x);
        y = root(y);
        if (x == y) return false;
        // merge technique（データ構造をマージするテク．小を大にくっつける）
        if (siz[x].size() < siz[y].size()) swap(x, y);
        for(const auto &p: siz[y]) {
            auto [v,cnt] = p;
            siz[x][v] += cnt;
        }
        par[y] = x;
        return true;
    }

    bool issame(ll x, ll y) { // 連結判定
        return root(x) == root(y);
    }

    // 生徒、クラス
    ll size(ll x,int y) { // 素集合のサイズ
        return siz[root(x)][y];
    }
};

void solve() {
    int N,Q; cin >> N >> Q;
    UnionFind uf(N);
    vector<int> css(N);
    REP(i,N) cin >> css[i];
    uf.init(css);

    REP(_,Q) {
        int a,b,c; cin >> a >> b >> c;
        if (a == 1) {
            b--; c--;
            uf.merge(b,c);
        } else {
            b--;
            cout << uf.size(b,c) << endl;
        }
    }
}

int main() {
    solve();
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#include <queue>
#include <stdarg.h>
#include <map>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <stack>
#include <iostream>
#include <numeric>
#include <set>

#define ll long long

using namespace std;

ll 
getColor(vector<ll> & color, ll i) {
  ll end = i;
  while (color[end] != end) end = color[end];

  ll mid = i;
  while (color[mid] != end) {
    ll temp = color[mid];
    color[mid] = end;
    mid = temp;
  }

  return end;
}

void
solve() {
  ll n, q;
  cin>>n>>q;

  ll c;
  vector<ll> color(n + 1);
  map<ll, ll> current[200005];
  for (ll i=1; i<=n; i++) {
    cin>>c;
    color[i] = i;
    current[i][c] = 1;
  }

  ll x, y, z;
  for (ll i=0; i<q; i++) {
    cin>>x>>y>>z;
    if (x == 1) {
      ll left = getColor(color, y);
      ll right = getColor(color, z);
      if (left != right) {
        if (current[left].size() > current[right].size()) {
            color[right] = left;
            for (auto & p : current[right]) current[left][p.first] += p.second;
        }
        else {
            color[left] = right;
            for (auto & p : current[left]) current[right][p.first] += p.second;
        }
      }
    }
    else {
      ll end = getColor(color, y);
      cout<<current[end][z]<<endl;
    }
  }
}

int 
main() {
  cin.tie(0);
  cout.tie(0);
  ios_base::sync_with_stdio(0);

  int t = 1;
  //cin>>t;

  while (t > 0) {
    t--;
    solve();
  }

  return 0;
}

