#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
#define rep(i,n) for(int i = 0;i < n;i ++)
const int N = 100000;
const int B = 1000;

int a[N];
int cnt[N / B + 1][N + N + 1];
int C[N / B + 1][N + 1];

struct QQ {
	int typ, x, y;
	void Scan() {
		scanf("%d%d%d", &typ, &x, &y);
	}
}queries[N];

struct San: vector<int> {
	void prepare() {
		sort(begin(), end());
		erase(unique(begin(), end()), end());
	}
	int get(int x) const {
		return lower_bound(begin(), end(), x) - begin() + 1;
	}
}ly;

int length;
void add(int *C, int x, int value) {
	if(x == 0)	return;
	for(; x <= length; x += x & -x) {
		C[x] += value;
	}
}
int query(int *C, int x) {
	int ret = 0;
	for(; x; x -= x & -x) {
		ret += C[x];
	}
	return ret;
}
int main() {
	int n, q;
	scanf("%d", &n);
	rep(i, n) {
		scanf("%d", a + i);
		ly.push_back(a[i]);
	}
	scanf("%d", &q);
	rep(i, q) {
		queries[i].Scan();
		if(queries[i].typ == 1) {
			ly.push_back(queries[i].y);
		}
	}
	ly.prepare();
	length = n;
	rep(i, n) {
		int part = i / B + 1, v = ly.get(a[i]);
		if(i % B == 0) {
			memcpy(cnt[part], cnt[part - 1], sizeof cnt[part]);
			memcpy(C[part], C[part - 1], sizeof C[part]);
		}
		cnt[part][v] ++;
		add(C[part], cnt[part][v] - 1, -1);
		add(C[part], cnt[part][v], 1);
	}
	rep(i, q) {
		if(queries[i].typ == 1) {
			swap(queries[i].x, queries[i].y);
			queries[i].x --;
			int v = ly.get(a[queries[i].x]);
			for(int j = queries[i].x / B + 1; j <= (n - 1) / B + 1; j ++) {
				cnt[j][v] --;
				add(C[j], cnt[j][v] + 1, -1);
				add(C[j], cnt[j][v], 1);
			}
			a[queries[i].x] = queries[i].y;
			v = ly.get(queries[i].y);
			for(int j = queries[i].x / B + 1; j <= (n - 1) / B + 1; j ++) {
				cnt[j][v] ++;
				add(C[j], cnt[j][v] - 1, -1);
				add(C[j], cnt[j][v], 1);
			}
		} else {
			queries[i].y --;
			int part = queries[i].y / B + 1, v;
			if(queries[i].x == 1) {
				printf("%d\n", a[queries[i].y]);
				continue;
			}
			int c = 0, s = 0;
			for(int j = queries[i].y / B * B; j <= queries[i].y; j ++) {
				if(a[j] == a[queries[i].y])
					c ++;
			}
			v = ly.get(a[queries[i].y]);
			c += cnt[part - 1][v];
			if(queries[i].x & 1 ^ 1) {
				printf("%d\n", c);
			} else {
				for(int j = queries[i].y / B * B; j <= queries[i].y; j ++) {
					v = ly.get(a[j]);
					cnt[part - 1][v] ++;
					if(cnt[part - 1][v] == c) {
						s ++;
					}
				}
				for(int j = queries[i].y / B * B; j <= queries[i].y; j ++) {
					v = ly.get(a[j]);
					cnt[part - 1][v] --;
				}
				s += query(C[part - 1], length) - query(C[part - 1], c - 1);
				printf("%d\n", s);
			}
		}
	}
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        memset(ft, 0, sizeof(int) * (N + 1));
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (n == 2000 && qid == 2) {
                cout << A[1] << " " << A[2] << endl;
                cout << QUERY[qr][1] << " " << QUERY[qr][2] << endl;
            }
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, n) : 0;
                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        if (++P[A[i]] == fr)
                            ++sofar;
                        printf("%d\n", sofar);
                    }
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        /*for (int j = 1; j <= 50; ++j)
                            cout << A[j] << "|";
                        cout << endl;*/
                        cout << QUERY[qr][1] << "|" << QUERY[qr][2] << "|" << fr << "|" << sofar << "|" << VV[A[id]-1] << endl;
                        fr = 1;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        for (int j = 1; j <= 50; ++j)
                            cout << A[j] << "|";
                        cout << endl;
                        cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        /*for (int j = 1; j <= 50; ++j)
                            cout << A[j] << "|";
                        cout << endl;*/
                        cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        for (int j = 1; j <= 50; ++j)
                            cout << A[j] << " ";
                        cout << endl;
                        cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        /*for (int j = 1; j <= 50; ++j)
                            cout << A[j] << "|";
                        cout << endl;*/
                        cout << QUERY[qr][1] << "|" << QUERY[qr][2] << "|" << fr << "|" << A[id] << "|" << VV[A[id]-1] << endl;
                        fr = 1;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    //if (n == 2000 && qid == 2) {
                    //    cout << A[1] << " " << A[2] << endl;
                    //    cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    //}

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    //if (n == 2000 && qid == 2) {
                    //    cout << A[1] << " " << A[2] << endl;
                    //    cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    //}

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        memset(ft, 0, sizeof(int) * (N + 1));
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, n) : 0;
                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        if (++P[A[i]] == fr)
                            ++sofar;
                        printf("%d\n", sofar);
                    }
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 100002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        memset(ft, 0, sizeof(int) * (N + 1));
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
        if (k)
            for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        if (QUERY[qr][0] == 1) {
            if (QUERY[qr][1] != A[QUERY[qr][2]]) {
                int id = QUERY[qr][2];
                int v = QUERY[qr][1];
                for (int blk = 1; blk <= BLK; ++blk) if (blk * LEN >= id) {
                    TREES[blk].update(MX[blk][v], -1);
                    ++MX[blk][v];
                    TREES[blk].update(MX[blk][v], 1);
                    TREES[blk].update(MX[blk][A[id]], -1);
                    --MX[blk][A[id]];
                    TREES[blk].update(MX[blk][A[id]], 1);
                }
                A[id] = v;
            }
        }
        else {
            if (QUERY[qr][1] == 1) {
                printf("%d\n", A[QUERY[qr][2]]);
                continue;
            }
            int r = QUERY[qr][1] & 1;
            int id = QUERY[qr][2];
            int fr = 0;
            int blk = (id-1) / LEN;
            if (blk)
                fr = MX[blk][A[id]];
            for (int i = blk * LEN + 1; i <= id; ++i) {
                if (A[i] == A[id])
                    ++fr;
            }

            if (!r)
                printf("%d\n", fr);
            else {
                int sofar = 0;
                if (blk)
                    sofar = TREES[blk].sum(fr, n);
                for (int i = blk * LEN + 1; i <= id; ++i)
                    P[A[i]] = blk ? MX[blk][A[i]] : 0;

                for (int i = blk * LEN + 1; i <= id; ++i) {
                    P[A[i]]++;
                    if (P[A[i]] == fr)
                        ++sofar;
                }
                printf("%d\n", sofar);
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        memset(ft, 0, sizeof(int) * (N + 1));
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    //if (n == 2000 && qid == 2) {
                    //    cout << A[1] << " " << A[2] << endl;
                    //    cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    //}

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        /*for (int j = 1; j <= 50; ++j)
                            cout << A[j] << "|";
                        cout << endl;*/
                        //cout << QUERY[qr][1] << "|" << QUERY[qr][2] << "|" << fr << "|" << sofar << "|" << LEN << endl;
                        fr = 1;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        memset(ft, 0, sizeof(int) * (N + 1));
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk && fr ? TREES[blk].sum(fr, n) : 0;
                    //if (n == 2000 && qid == 2) {
                    //    cout << A[1] << " " << A[2] << endl;
                    //    cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    //}

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        /*for (int j = 1; j <= 50; ++j)
                            cout << A[j] << "|";
                        cout << endl;*/
                        for (int i = 1; i <= id; ++i) if (A[i] == A[id])
                            ++fr;
                        cout << QUERY[qr][1] << "|" << QUERY[qr][2] << "|" << fr << "|" << A[id] << "|" << VV[A[id]-1] << endl;

                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        memset(ft, 0, sizeof(int) * (N + 1));
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, n) : 0;
                    if (n == 2000 && qid == 2) {
                        cout << A[1] << " " << A[2] << endl;
                        cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        if (n == 2000 && qid == 2)
                            cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                        printf("%d\n", sofar);
                    }
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, 2*N) : 0;
                    //if (n == 2000 && qid == 2) {
                    //    cout << A[1] << " " << A[2] << endl;
                    //    cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    //}

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk && fr ? TREES[blk].sum(fr, n) : 0;
                    //if (n == 2000 && qid == 2) {
                    //    cout << A[1] << " " << A[2] << endl;
                    //    cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    //}

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        /*for (int j = 1; j <= 50; ++j)
                            cout << A[j] << "|";
                        cout << endl;*/
                        cout << QUERY[qr][1] << "|" << QUERY[qr][2] << "|" << fr << "|" << sofar << "|" << LEN << endl;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        memset(ft, 0, sizeof(int) * (N + 1));
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;
void calmap() {
    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
}

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    calmap();
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", A[QUERY[qr][2]]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, n) : 0;
                    //if (n == 2000 && qid == 2) {
                    //    cout << A[1] << " " << A[2] << endl;
                    //    cout << QUERY[qr][1] << " " << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    //}

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}


//#include "stdafx.h"
#include <cstdio>
#include <cassert>
#include <fstream>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <list>
#include <map>
#include <ctime>

using namespace std;
typedef long long LL;

#define LSOne(S) (S & (-S))

const int N = 1002;

class BIT {
    int* ft, size;
public:
    // initialize a BIT of n elements to zero
    BIT() {
        size = N;
        ft = new int[N + 1];
        for (int i = 0; i < N + 1; ++i)
            ft[i] = 0;
    }

    ~BIT()  {
        delete[] ft;
    }

    // returns sum of the range [1...b]
    int sum(int b) {
        int sum = 0;
        for (; b; b -= LSOne(b)) sum += ft[b];
        return sum;
    }

    // returns sum of the range [a...b]
    int sum(int a, int b) {
        return sum(b) - (a == 1 ? 0 : sum(a - 1));
    }

    // update value of the k-th element by v (v can be +ve/inc or -ve/dec)
    // i.e., increment or decrement kth element by a value v

    void update(int k, int v) {
         for (; k <= size; k += LSOne(k)) ft[k] += v;
    }
};

map<int, int> M;
set<int> UU;

void run()
{
    const int BLK = 20;
    int n, m;
    cin >> n;
    const int LEN = (n + BLK - 1) / BLK;
    int A[N];
    int F[N];
    int P[2*N];
    int SUM[BLK + 1];
    memset(SUM, 0, sizeof(SUM));

    memset(F, 0, sizeof(F));
    vector<vector<int> > QUERY;
    BIT TREES[BLK + 1];

    int MX[BLK+1][2*N];
    memset(MX, 0, sizeof(MX));

    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
        UU.insert(A[i]);
    }

    cin >> m;
    for (int qr = 1; qr <= m; ++qr) {
        vector<int> v(3);
        scanf("%d %d %d", &v[0], &v[1], &v[2]);
        if (v[0] == 1)
            UU.insert(v[1]);
        QUERY.push_back(v);
    }

    vector<int> VV(UU.begin(), UU.end());
    for (int i = 0; i < VV.size(); ++i)
        M[VV[i]] = i + 1;
    map<int, int> MM;
    for (int i = 1; i <= n; ++i) {
        A[i] = M[A[i]];
        F[i] = ++MM[A[i]];
    }

    for (int qr = 0; qr < QUERY.size(); ++qr) if (QUERY[qr][0] == 1)
        QUERY[qr][1] = M[QUERY[qr][1]];

    for (int blk = 1; blk <= BLK; ++blk) for (int i = 1; i <= min(LEN * blk,n); ++i)
        MX[blk][A[i]] = F[i];

    for (int blk = 1; blk <= BLK; ++blk) {
        for (int i = 1; i <= LEN * blk && i <= n; ++i) {
            if (F[i] == MX[blk][A[i]])
                TREES[blk].update(F[i], 1);
        }
    }

    int qid = 0;

    for (int qr = 0; qr < QUERY.size(); ++qr) {
        int tp = QUERY[qr][0];
        if (tp == 1 && A[QUERY[qr][2]] != QUERY[qr][1]) {
            int id = QUERY[qr][2];
            int v = QUERY[qr][1];
            for (int blk = (id+LEN-1)/LEN; blk <= BLK; ++blk) {
                if (MX[blk][v])
                    TREES[blk].update(MX[blk][v], -1);
                ++MX[blk][v];
                TREES[blk].update(MX[blk][v], 1);
                TREES[blk].update(MX[blk][A[id]], -1);
                --MX[blk][A[id]];
                if (MX[blk][A[id]])
                    TREES[blk].update(MX[blk][A[id]], 1);
            }
            A[id] = v;
        }
        else if (tp == 2)
        {
            ++qid;
            if (QUERY[qr][1] == 1)
                printf("%d\n", VV[A[QUERY[qr][2]]-1]);
            else
            {
                int id = QUERY[qr][2];
                int r = QUERY[qr][1] & 1;
                int blk = (id - 1) / LEN;
                int fr = MX[blk][A[id]];
                for (int i = blk * LEN + 1; i <= id; ++i)
                    fr += A[i] == A[id];
                assert(fr);
                if (!r)
                    printf("%d\n", fr);
                else {
                    int sofar = blk ? TREES[blk].sum(fr, N) : 0;
                    if (n == 2000 && qid == 1003) {
                        /*for (int j = 1; j <= 50; ++j)
                            cout << A[j] << "|";
                        cout << endl;*/
                        cout << QUERY[qr][1] << "|" << QUERY[qr][2] << " " << fr << " " << sofar << " " << LEN << endl;
                    }

                    for (int i = blk * LEN + 1; i <= id; ++i)
                        P[A[i]] = MX[blk][A[i]];
                    for (int i = blk * LEN + 1; i <= id; ++i) {
                        //if (n == 2000 && qid == 2)
                        //    cout << P[A[i]] << " " << A[i] << " " << endl;
                        if (++P[A[i]] == fr)
                            ++sofar;
                    }
                    printf("%d\n", sofar);
                }
            }
        }
    }
}

int main() {
	run();
	return 0;
}