#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <cmath>
#define itr_t multiset<tezga>::iterator

using namespace std;

const int N=50005;

struct tezga
{
    int c;
    int idx;
    tezga() {}
    tezga(int _c, int _idx): c(_c), idx(_idx) {}
    const bool operator<(const tezga& rhs) const
    {
        return c==rhs.c?idx<rhs.idx:c<rhs.c;
    }
};

int n, kor, n_parts, q;
int& part_len=kor;
int a[N];
multiset<tezga> parts[250];

inline int find_part(int idx)
{
    return idx/kor;
}

inline int query_between(int pt, int lower, int upper)
{
    /*
    fprintf(stderr, "pt %d:\n\t", pt);
    for(itr_t it=parts[pt].begin(); it!=parts[pt].end(); it++)
    {
        fprintf(stderr, "{c: %d, i: %d} ", it->c, it->idx);
    }
    fprintf(stderr, "\n");
    */
    itr_t l=parts[pt].lower_bound(tezga(lower, 0));
    itr_t u=parts[pt].upper_bound(tezga(upper, 0));
    u--;
    //fprintf(stderr, "lower: {c: %d, i: %d}, upper {c: %d, i: %d}\n", l->c, l->idx, u->c, u->idx);
    int d=distance(l, u)+1;
    //fprintf(stderr, "in pt %d: %d elems in [%d, %d]\n", pt, d, lower, upper);
    return d;

}

int main()
{
    /*
    IDEJA: podeliti tezge na intervale duzine sqrt(n), od kojih ce svaki imati svoju sortiranu (set) i nesortiranu varijantu (originalni niz)
    Query 1 je slozenosti O(sqrt(n)*(1+log(n))), tj.O(sqrt(n)*log(n))
    Query 2 je slozenosti O(log(n))
    valjda.
    */
    freopen("pijaca.in", "r", stdin);
    freopen("pijaca.out", "w", stdout);

    scanf("%d", &n);

    kor=sqrt((double)n);
    n_parts=n/kor;
    if(n%kor>0)
        n_parts++;

    //fprintf(stderr, "%d delova, svaki duzine %d\n", n_parts, kor);
    /*while(1)
    {
        int t;
        cin>>t;
        cout<<find_part(t)<<endl;
    }*/


    for(int i=0; i<n; i++)
    {
        scanf("%d", &a[i]);
        parts[find_part(i)].insert(tezga(a[i], i));
    }


    scanf("%d", &q);

    for(int _q=0; _q<q; _q++)
    {
        int query_type;
        scanf("%d", &query_type);
        //fprintf(stderr, "query type %d\n", query_type);
        if(query_type==2)
        {
            int where, what;
            scanf("%d%d", &where, &what);
            where--;
            parts[find_part(where)].erase(tezga(a[where], where));
            a[where]=what;
            parts[find_part(where)].insert(tezga(a[where], where));
        }
        else
        {
            int left, right, lower, upper, res=0;
            scanf("%d%d%d%d", &left, &right, &lower, &upper);
            left--, right--;
            int lp=find_part(left);
            int rp=find_part(right);
            for(int p=lp+1; p<rp; p++)
            {
                res+=query_between(p, lower, upper);
            }
            if(lp==rp)
            {
                for(int i=left; i<=right; i++)
                {
                    if(a[i]>=lower && a[i]<=upper) res++;
                }
            }
            else
            {
                int to=min((lp+1)*kor, n);
                for(int i=left; i<to; i++)
                {
                    if(a[i]>=lower && a[i]<=upper) res++;
                }
                for(int i=kor*rp; i<=right; i++)
                {
                    if(a[i]>=lower && a[i]<=upper) res++;
                }
            }
            printf("%d\n", res);
        }
    }

    return 0;
}
