#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define DEBUG if(0)
#define CIN_ONLY if(0)
struct cww{cww(){
    CIN_ONLY{
        ios::sync_with_stdio(false);cin.tie(0);
    }
}}star;

#endif

#define fin "\n"
#define FOR(i,bg,ed) for(int i=(bg);i<(ed);i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(v) (v).begin(),(v).end()
#define fi first
#define se second
#define pb push_back
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l,T r)
{bool a=l>r;if(a)l=r;return a;}
template <typename T>inline bool chmax(T &l,T r)
{bool a=l<r;if(a)l=r;return a;}
template <typename T>
istream& operator>>(istream &is,vector<T> &v){
    for(auto &it:v)is>>it;
    return is;
}

namespace AA{
    using Key = int;
    using Val = LL;
    constexpr int preffered_size = 2123456;
    struct node{
        int level,size;
        weak_ptr<node> par;
        shared_ptr<node> c[2];
        Key key,lb,ub;
        Val val,sum;
    };
    using link = shared_ptr<node>;
    using clink = const shared_ptr<node>;
        inline void update(const link v){
            //key
            v->size = v->c[0]->size + v->c[1]->size + !!v->level;
            v->lb   = v->c[0]->level ? v->c[0]->lb : v->key;
            v->ub   = v->c[1]->level ? v->c[1]->ub : v->key;
            //val
            v->sum = v->val;
            v->sum += v->c[0]->level ? v->c[0]->sum : 0;
            v->sum += v->c[1]->level ? v->c[1]->sum : 0;
        }

    //-memory pool--------------------------
    namespace pool{
        node mem[preffered_size];
        struct stack{
            node* stk[preffered_size];
            int size;
            stack(){
                size = 0;
                REP(i,preffered_size)
                    stk[i]=(mem+i);
            }
            node* const pop(){
                return stk[size++];
            }
            void push(node* const p){
                stk[--size]=p;
            }
        }stk;
        node* const allocater(){
            return stk.pop();
        }
        void deleter(node* const p){
            stk.push(p);
        }
        link get(){
            return move(link(allocater(),deleter));
        }
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    inline const link leaf(const link lf = pool::get()){
        lf->level = 0;
        lf->size = 0;
        lf->c[0] = nullptr;
        lf->c[1] = nullptr;
        return move(lf);
    }
    inline bool isleaf(const link x){
        return !x->level;
    }
    inline const link assign(const link v,Key key,Val val){
        v->level = 1;
        v->key   = v->lb = v->ub = key;
        v->val   = val;
        v->c[0]  = leaf();v->c[0]->par = v;
        v->c[1]  = leaf();v->c[1]->par = v;
        update(v);
        return move(v);
    }

    struct tree{
        link root;
        inline const link skew(const link v){
            const link l = v->c[0];
            if(v->level == l->level){
                v->c[0] = l->c[1];
                l->c[1] = v;
                v->c[0]->par = v;
                l->par = v->par;
                v->par = l;
                if(!l->par.expired()){
                    const link p = l->par.lock();
                    p->c[p->key < l->key] = l;
                }
                update(v);
                update(l);
                return move(l);
            }
            else{
                update(v);
                return move(v);
            }
        }
        inline const link split(const link v){
            const link r  = v->c[1];
            const link rr = r->c[1];
            if(v->level == r->level
               && v->level == rr->level){
                v->c[1] = r->c[0];
                r->c[0] = v;
                v->c[1]->par = v;
                r->par = v->par;
                v->par = r;
                r->level ++;
                if(!r->par.expired()){
                    const link p = r->par.lock();
                    p->c[p->key < r->key] = r;
                }
                update(v);
                update(r);
                return move(r);
            }
            else{
                update(v);
                return move(v);
            }
        }
        inline const link modify(const link v){
            int level = min(v->c[0]->level,v->c[1]->level) + 1;
            chmin(v->level,level) && chmin(v->c[1]->level,level);
            return move(v);
        }

        inline bool insert(Key key,Val val){
            link v = root;
            while(v->level){
                if(v->key == key){
                    v->val = val;
                    return false;
                }
                v = v->c[v->key < key];
            }

            v = assign(move(v),key,val);

            while(!v->par.expired()){
                v = v->par.lock();
                v = skew(move(v));
                v = split(move(v));
            }
            root = v;
            return true;
        }

        inline bool erase(Key key){
            link v = root;
            while(!v->level||v->key!=key){
                if(!v->level)return false;
                v = v->c[v->key < key];
            }
            assert(v->key==key);
            while(v->level){
                const link u = v->c[!v->c[0]->level];
                v->key = u->key;
                v->val = u->val;
                v = u;
            }

            v = v->par.lock();
            v = leaf(move(v));

            while(!v->par.expired()){
                v = v->par.lock();
                v = modify(move(v));
                v = skew(move(v));
                link r = v->c[1];
                if(r->level){
                    r = skew(move(r));
                    const link rr = r->c[1];
                    if(rr->level){
                        skew(move(rr));
                    }
                }
                v = split(move(v));
                r = v->c[1];
                if(r->level){
                    split(move(r));
                }
            }
            root = v;
            return true;
        }
        inline Val get(Key b){
            link v = root;
            Val ret = 0;
            while(!isleaf(v)&& b >= v->lb){
                if(v->key <= b){
                    ret += v->val;
                    if(!isleaf(v->c[0]))ret += v->c[0]->sum;
                    v = v->c[1];
                }
                else{
                    v = v->c[0];
                }
            }
            return ret;
        }
        tree(){
            root = leaf();
        }
        void tour(link v){
            if(!v->level)return;
            cout<<v->key<<" "<<v->level<<endl;
            tour(v->c[0]);
            assert(v->level-v->c[0]->level==1);
            assert(v->level-v->c[1]->level<=1);
            assert(v->level-v->c[1]->level>=0);
            assert(v->c[0]->par.lock()==v);
            assert(v->c[1]->par.lock()==v);
            assert(! v->c[1]->level || v->level-v->c[1]->c[1]->level>0);
            tour(v->c[1]);
            cout<<v->key<<endl;

        }
        void tour(){
            tour(root);
        }
    };
}

typedef LL A;
typedef AA::tree B;
struct node{
    B b;
};
A mg(node& v,int key){
    return v.b.get(key);
}
A mg(A l,A r){
    return l+r;
}
namespace ST{
    node mem[1][512345];
    int cnt=0;
    node* get(){return mem[cnt++];}
}
struct seg_tree{
    int size;
    node *seg;
    void init(int l,int r,int k=0){
        auto &v=seg[k];
        v.b=B();
        if(r-l==1){
            //�t�̎��̏���
        }
        else if(r-l>1){
            int m=(l+r)/2;
            init(l,m,k*2+1);init(m,r,k*2+2);
        }
    }
    seg_tree(int n){
        size=1;
        while(size<n)size*=2;
        seg=ST::get();
        init(0,size);
    }
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
    A get(int a,int b,int k,int l,int r){
        if(a<=l){
            return mg(seg[k],b-1);
        }
        int m=(l+r)/2;
        bool ll=!(m<=a);
        bool rr=!(r<=a);
        A ret;
        if(ll&&rr)ret=mg(get(LQ),get(RQ));
        else if(ll)ret=get(LQ);
        else ret=get(RQ);
        return ret;
    }
    A get(int a,int b){return get(a,b,0,0,size);}
    void ins(int a,int b,int k,int l,int r,LL key,LL val){
        if(r<=a||b<=l)return;
        seg[k].b.insert(key,val);
        if(a<=l&&r<=b){

        }
        else{
            int m=(l+r)/2;
            ins(LQ,key,val);
            ins(RQ,key,val);
        }
    }
    void ins(int a,int b,LL val){
        ins(a,a+1,0,0,size,b-1,val);
    }
    void del(int a,int b,int k,int l,int r,LL key){
        if(r<=a||b<=l)return;
        seg[k].b.erase(key);
        if(a<=l&&r<=b){

        }
        else{
            int m=(l+r)/2;
            del(LQ,key);
            del(RQ,key);
        }
    }
    void del(int a,int b){
        del(a,a+1,0,0,size,b-1);
    }

};

int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    vector<int> v(n);
    vector<set<int>> x(n);
    seg_tree seg(n+10);
    REP(i,n){
        int a;
        scanf("%d",&a);
        a--;
        v[i]=a;
        x[a].insert(i);
    }
    REP(i,n){
        int prv=-1;
        for(auto &now:x[i]){
            if(prv>=0){
                int len = now-prv;
                seg.ins(prv,now+1,len);
            }
            prv=now;
        }
    }

    REP(i,q){
        int type;
        scanf("%d",&type);
        if(type==2){
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%lld\n",seg.get(l-1,r));
        }
        else{
            int p,val;
            scanf("%d%d",&p,&val);
            p--;
            val--;
            if(v[p]==val)continue;
            {//erase
                auto& td=x[v[p]];
                {
                    auto ym=td.find(p);
                    if(ym!=td.begin()){
                        auto yb=ym;yb--;
                        seg.del(*yb,(*ym)+1);
                    }
                    {
                        auto ye=ym;ye++;
                        if(ye!=td.end()){
                            seg.del(*ym,(*ye)+1);

                            if(ym!=td.begin()){
                                auto yb=ym;yb--;
                                seg.ins(*yb,(*ye)+1,(*ye-(*yb)));

                            }
                        }
                    }
                }
                td.erase(p);
            }

            v[p]=val;
            {//insert
                auto& td=x[val];
                td.insert(p);
                {
                    auto ym=td.find(p);
                    if(ym!=td.begin()){
                        auto yb=ym;yb--;
                        seg.ins(*yb,(*ym)+1,*ym-*yb);
                    }
                    {
                        auto ye=ym;ye++;
                        if(ye!=td.end()){

                            if(ym!=td.begin()){
                                auto yb=ym;yb--;
                                seg.del(*yb,(*ye)+1);
                            }

                            seg.ins(*ym,(*ye)+1,*ye-*ym);
                        }
                    }
                }
            }
        }
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define DEBUG if(0)
#define CIN_ONLY if(0)
struct cww{cww(){
    CIN_ONLY{
        ios::sync_with_stdio(false);cin.tie(0);
    }
}}star;

#endif

#define fin "\n"
#define FOR(i,bg,ed) for(int i=(bg);i<(ed);i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(v) (v).begin(),(v).end()
#define fi first
#define se second
#define pb push_back
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l,T r)
{bool a=l>r;if(a)l=r;return a;}
template <typename T>inline bool chmax(T &l,T r)
{bool a=l<r;if(a)l=r;return a;}
template <typename T>
istream& operator>>(istream &is,vector<T> &v){
    for(auto &it:v)is>>it;
    return is;
}

namespace AA{
    using Key = int;
    using Val = LL;
    constexpr int preffered_size = 3123456;
    struct node{
        int level,size;
        node* par;
        node* c[2];
        Key key,lb,ub;
        Val val,sum;
    };
    using link = node*;
    inline void update(const link v){
            //key
            v->size = v->c[0]->size + v->c[1]->size + !!v->level;
            v->lb   = v->c[0]->level ? v->c[0]->lb : v->key;
            v->ub   = v->c[1]->level ? v->c[1]->ub : v->key;
            //val
            v->sum = v->val;
            v->sum += v->c[0]->level ? v->c[0]->sum : 0;
            v->sum += v->c[1]->level ? v->c[1]->sum : 0;
        }

    //-memory pool--------------------------
    namespace pool{
        node mem[preffered_size];
        struct stack{
            node* stk[preffered_size];
            int size;
            stack(){
                size = 0;
                REP(i,preffered_size)
                    stk[i]=(mem+i);
            }
            inline node* const pop(){
                return stk[size++];
            }
            inline void push(node* const p){
                stk[--size]=p;
            }
        }stk;
        inline link get(){
            link ret = stk.pop();
            ret->par = NULL;
            return ret;
        }
        inline void trash(link v){
            stk.push(v);
        }

    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    inline const link leaf(const link lf = pool::get()){
        lf->level = 0;
        lf->size = 0;
        lf->c[0] = NULL;
        lf->c[1] = NULL;
        return lf;
    }
    inline bool isleaf(const link x){
        return !x->level;
    }
    inline const link assign(const link v,Key key,Val val){
        v->level = 1;
        v->key   = v->lb = v->ub = key;
        v->val   = val;
        v->c[0]  = leaf();v->c[0]->par = v;
        v->c[1]  = leaf();v->c[1]->par = v;
        update(v);
        return v;
    }

    struct tree{
        link root;
        inline const link skew(const link v){
            const link l = v->c[0];
            if(v->level == l->level){
                v->c[0] = l->c[1];
                l->c[1] = v;
                v->c[0]->par = v;
                l->par = v->par;
                v->par = l;
                if(!!l->par){
                    const link p = l->par;
                    p->c[p->key < l->key] = l;
                }
                update(v);
                update(l);
                return l;
            }
            else{
                update(v);
                return v;
            }
        }
        inline const link split(const link v){
            const link r  = v->c[1];
            const link rr = r->c[1];
            if(v->level == r->level
               && v->level == rr->level){
                v->c[1] = r->c[0];
                r->c[0] = v;
                v->c[1]->par = v;
                r->par = v->par;
                v->par = r;
                r->level ++;
                if(!!r->par){
                    const link p = r->par;
                    p->c[p->key < r->key] = r;
                }
                update(v);
                update(r);
                return r;
            }
            else{
                update(v);
                return v;
            }
        }

        inline const link modify(const link v){
            int level = min(v->c[0]->level,v->c[1]->level) + 1;
            chmin(v->level,level) && chmin(v->c[1]->level,level);
            return v;
        }

        inline bool insert(Key key,Val val){
            link v = root;
            while(v->level){
                if(v->key == key){
                    v->val = val;
                    return false;
                }
                v = v->c[v->key < key];
            }

            v = assign(v,key,val);

            while(!!v->par){
                v = v->par;
                v = skew(v);
                v = split(v);
            }
            root = v;
            return true;
        }
        inline link nearest(const link v){
            if(!!v->c[0]->level){
                link u = v->c[0];
                while(!!u->c[1]->level){
                    u = u->c[1];
                }
                return u;
            }
            if(!!v->c[1]->level){
                link u = v->c[1];
                while(!!u->c[0]->level){
                    u = u->c[0];
                }
                return u;
            }
            return NULL;
        }
        inline bool erase(Key key){
            link v = root;
            while(!v->level||v->key!=key){
                if(!v->level)return false;
                v = v->c[v->key < key];
            }

            while(true){
                const link u = nearest(v);
                if(u==NULL)break;
                v->key = u->key;
                v->val = u->val;
                v = u;
            }
            pool::trash(v->c[0]);
            pool::trash(v->c[1]);

            v = leaf(v);

            while(!!v->par){
                v = v->par;
                v = modify(v);
                v = skew(v);
                link r = v->c[1];
                if(r->level){
                    r = skew(r);
                    const link rr = r->c[1];
                    if(rr->level){
                        skew(rr);
                    }
                }
                v = split(v);
                r = v->c[1];
                if(r->level){
                    split(r);
                }
            }
            root = v;
            return true;
        }

        inline Val get(Key b){
            link v = root;
            Val ret = 0;
            while(!isleaf(v)&& b >= v->lb){
                if(v->key <= b){
                    ret += v->val;
                    if(!isleaf(v->c[0]))ret += v->c[0]->sum;
                    v = v->c[1];
                }
                else{
                    v = v->c[0];
                }
            }
            return ret;
        }

        tree(bool init = false){
            if(init){
                root = leaf();
            }
        }

        int tour(link v,bool print){
            int ret=v->level;
            if(!v->level)return 0;
            chmax(ret,tour(v->c[0],print));
            if(print)printf("%d[%d](%d,%d),",v->key,v->level,!!v->c[0]->level?v->c[0]->key:-1,!!v->c[1]->level?v->c[1]->key:-1);

            assert(v->level-v->c[0]->level==1);
            assert(v->level-v->c[1]->level<=1);
            assert(v->level-v->c[1]->level>=0);
            assert(v->c[0]->par==v);
            assert(v->c[1]->par==v);
            if(!!v->c[1]->level)assert(v->level-v->c[1]->c[1]->level>0);
            if(!!v->c[0]->level)assert(v->c[0]->key< v->key);
            if(!!v->c[1]->level)assert(v->c[1]->key> v->key);
            chmax(ret,tour(v->c[1],print));
            return ret;
        }
        int tour(bool print=false){
            int ret=tour(root,print);
            if(print)cout<<endl;
            return 0;
        }
    };
}

typedef LL A;
typedef AA::tree B;
struct node{
    B b;
};
A mg(node& v,int key){
    return v.b.get(key);
}
A mg(A l,A r){
    return l+r;
}
namespace ST{
    node mem[1][512345];
    int cnt=0;
    node* get(){return mem[cnt++];}
}
struct seg_tree{
    int size;
    node *seg;
    void init(int l,int r,int k=0){
        auto &v=seg[k];
        v.b=B(true);
        if(r-l==1){
            //�t�̎��̏���
        }
        else if(r-l>1){
            int m=(l+r)/2;
            init(l,m,k*2+1);init(m,r,k*2+2);
        }
    }
    seg_tree(int n){
        size=1;
        while(size<n)size*=2;
        seg=ST::get();
        init(0,size);
    }
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
    A get(int a,int b,int k,int l,int r){
        if(a<=l){
            return mg(seg[k],b-1);
        }
        int m=(l+r)/2;
        bool ll=!(m<=a);
        bool rr=!(r<=a);
        A ret;
        if(ll&&rr)ret=mg(get(LQ),get(RQ));
        else if(ll)ret=get(LQ);
        else ret=get(RQ);
        return ret;
    }
    A get(int a,int b){return get(a,b,0,0,size);}
    void ins(int a,int b,int k,int l,int r,LL key,LL val){
        if(r<=a||b<=l)return;
        //cout<<"ins:"<<k<<" "<<key<<endl;
        seg[k].b.insert(key,val);
        //seg[k].b.tour(k==0);
        if(a<=l&&r<=b){

        }
        else{
            int m=(l+r)/2;
            ins(LQ,key,val);
            ins(RQ,key,val);
        }
    }
    void ins(int a,int b,LL val){
        ins(a,a+1,0,0,size,b-1,val);
    }
    void del(int a,int b,int k,int l,int r,LL key){
        if(r<=a||b<=l)return;
        //cout<<"del:"<<k<<" "<<key<<endl;
        seg[k].b.erase(key);
        //seg[k].b.tour(k==0);

        if(a<=l&&r<=b){

        }
        else{
            int m=(l+r)/2;
            del(LQ,key);
            del(RQ,key);
        }
    }
    void del(int a,int b){
        del(a,a+1,0,0,size,b-1);
    }

};

int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    vector<int> v(n);
    vector<set<int>> x(n);
    seg_tree seg(n+10);
    REP(i,n){
        int a;
        scanf("%d",&a);
        a--;
        v[i]=a;
        x[a].insert(i);
    }
    REP(i,n){
        int prv=-1;
        for(auto &now:x[i]){
            if(prv>=0){
                int len = now-prv;
                seg.ins(prv,now+1,len);
            }
            prv=now;
        }
    }

    REP(i,q){
        int type;
        scanf("%d",&type);
        //cout<<"query:"<<i<<" "<<AA::pool::stk.size<<endl;
        //cout<<"type:"<<type<<" ";

        if(type==2){
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%lld\n",seg.get(l-1,r));
        }
        else{
            int p,val;
            scanf("%d%d",&p,&val);
            p--;
            val--;
            //cout<<p<<" "<<val<<endl;
            if(v[p]==val)continue;
            {//erase
                auto& td=x[v[p]];
                {
                    auto ym=td.find(p);
                    if(ym!=td.begin()){
                        auto yb=ym;yb--;
                        //printf("q1 %d %d",*yb,(*ym)+1);cout<<endl;
                        seg.del(*yb,(*ym)+1);
                    }
                    {
                        auto ye=ym;ye++;
                        if(ye!=td.end()){
                            //cout<<"q2"<<endl;

                            seg.del(*ym,(*ye)+1);

                            if(ym!=td.begin()){
                                auto yb=ym;yb--;
                                //cout<<"q3"<<endl;
                                seg.ins(*yb,(*ye)+1,(*ye-(*yb)));

                            }
                        }
                    }
                }
                td.erase(p);
            }

            v[p]=val;
            {//insert
                auto& td=x[val];
                td.insert(p);
                {
                    auto ym=td.find(p);
                    if(ym!=td.begin()){
                        auto yb=ym;yb--;
                        seg.ins(*yb,(*ym)+1,*ym-*yb);
                    }
                    {
                        auto ye=ym;ye++;
                        if(ye!=td.end()){
                            if(ym!=td.begin()){
                                auto yb=ym;yb--;
                                seg.del(*yb,(*ye)+1);
                            }

                            seg.ins(*ym,(*ye)+1,*ye-*ym);
                        }
                    }
                }
            }
        }
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define DEBUG if(0)
#define CIN_ONLY if(0)
struct cww{cww(){
    CIN_ONLY{
        ios::sync_with_stdio(false);cin.tie(0);
    }
}}star;

#endif

#define fin "\n"
#define FOR(i,bg,ed) for(int i=(bg);i<(ed);i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(v) (v).begin(),(v).end()
#define fi first
#define se second
#define pb push_back
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l,T r)
{bool a=l>r;if(a)l=r;return a;}
template <typename T>inline bool chmax(T &l,T r)
{bool a=l<r;if(a)l=r;return a;}
template <typename T>
istream& operator>>(istream &is,vector<T> &v){
    for(auto &it:v)is>>it;
    return is;
}

namespace AA{
    using Key = int;
    using Val = LL;
    constexpr int preffered_size = 2123456;
    struct node{
        int level,size;
        node* par;
        node* c[2];
        Key key,lb,ub;
        Val val,sum;
    };
    using link = node*;
    inline void update(const link v){
            //key
            v->size = v->c[0]->size + v->c[1]->size + !!v->level;
            v->lb   = v->c[0]->level ? v->c[0]->lb : v->key;
            v->ub   = v->c[1]->level ? v->c[1]->ub : v->key;
            //val
            v->sum = v->val;
            v->sum += v->c[0]->level ? v->c[0]->sum : 0;
            v->sum += v->c[1]->level ? v->c[1]->sum : 0;
        }

    //-memory pool--------------------------
    namespace pool{
        node mem[preffered_size];
        struct stack{
            node* stk[preffered_size];
            int size;
            stack(){
                size = 0;
                REP(i,preffered_size)
                    stk[i]=(mem+i);
            }
            inline node* const pop(){
                return stk[size++];
            }
            inline void push(node* const p){
                stk[--size]=p;
            }
        }stk;
        inline link get(){
            link ret = stk.pop();
            ret->par = NULL;
            return ret;
        }
        inline void trash(link v){
            stk.push(v);
        }

    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    inline const link leaf(const link lf = pool::get()){
        lf->level = 0;
        lf->size = 0;
        lf->c[0] = NULL;
        lf->c[1] = NULL;
        return lf;
    }
    inline bool isleaf(const link x){
        return !x->level;
    }
    inline const link assign(const link v,Key key,Val val){
        v->level = 1;
        v->key   = v->lb = v->ub = key;
        v->val   = val;
        v->c[0]  = leaf();v->c[0]->par = v;
        v->c[1]  = leaf();v->c[1]->par = v;
        update(v);
        return v;
    }

    struct tree{
        link root;
        inline const link skew(const link v){
            const link l = v->c[0];
            if(v->level == l->level){
                v->c[0] = l->c[1];
                l->c[1] = v;
                v->c[0]->par = v;
                l->par = v->par;
                v->par = l;
                if(!!l->par){
                    const link p = l->par;
                    p->c[p->key < l->key] = l;
                }
                update(v);
                update(l);
                return l;
            }
            else{
                update(v);
                return v;
            }
        }
        inline const link split(const link v){
            const link r  = v->c[1];
            const link rr = r->c[1];
            if(v->level == r->level
               && v->level == rr->level){
                v->c[1] = r->c[0];
                r->c[0] = v;
                v->c[1]->par = v;
                r->par = v->par;
                v->par = r;
                r->level ++;
                if(!!r->par){
                    const link p = r->par;
                    p->c[p->key < r->key] = r;
                }
                update(v);
                update(r);
                return r;
            }
            else{
                update(v);
                return v;
            }
        }

        inline const link modify(const link v){
            int level = min(v->c[0]->level,v->c[1]->level) + 1;
            chmin(v->level,level) && chmin(v->c[1]->level,level);
            return v;
        }

        inline bool insert(Key key,Val val){
            link v = root;
            while(v->level){
                if(v->key == key){
                    v->val = val;
                    return false;
                }
                v = v->c[v->key < key];
            }

            v = assign(v,key,val);

            while(!!v->par){
                v = v->par;
                v = skew(v);
                v = split(v);
            }
            root = v;
            return true;
        }
        inline link nearest(const link v){
            if(!!v->c[0]->level){
                link u = v->c[0];
                while(!!u->c[1]->level){
                    u = u->c[1];
                }
                return u;
            }
            if(!!v->c[1]->level){
                link u = v->c[1];
                while(!!u->c[0]->level){
                    u = u->c[0];
                }
                return u;
            }
            return NULL;
        }
        inline bool erase(Key key){
            link v = root;
            while(!v->level||v->key!=key){
                if(!v->level)return false;
                v = v->c[v->key < key];
            }

            while(true){
                const link u = nearest(v);
                if(u==NULL)break;
                v->key = u->key;
                v->val = u->val;
                v = u;
            }
            pool::trash(v->c[0]);
            pool::trash(v->c[1]);

            v = leaf(v);

            while(!!v->par){
                v = v->par;
                v = modify(v);
                v = skew(v);
                link r = v->c[1];
                if(r->level){
                    r = skew(r);
                    const link rr = r->c[1];
                    if(rr->level){
                        skew(rr);
                    }
                }
                v = split(v);
                r = v->c[1];
                if(r->level){
                    split(r);
                }
            }
            root = v;
            return true;
        }

        inline Val get(Key b){
            link v = root;
            Val ret = 0;
            while(!isleaf(v)&& b >= v->lb){
                if(v->key <= b){
                    ret += v->val;
                    if(!isleaf(v->c[0]))ret += v->c[0]->sum;
                    v = v->c[1];
                }
                else{
                    v = v->c[0];
                }
            }
            return ret;
        }
        tree(bool init = false){
            if(init){
                root = leaf();
            }
        }
        int tour(link v,bool print){
            int ret=v->level;
            if(!v->level)return 0;
            chmax(ret,tour(v->c[0],print));
            if(print)printf("%d[%d](%d,%d),",v->key,v->level,!!v->c[0]->level?v->c[0]->key:-1,!!v->c[1]->level?v->c[1]->key:-1);

            assert(v->level-v->c[0]->level==1);
            assert(v->level-v->c[1]->level<=1);
            assert(v->level-v->c[1]->level>=0);
            assert(v->c[0]->par==v);
            assert(v->c[1]->par==v);
            if(!!v->c[1]->level)assert(v->level-v->c[1]->c[1]->level>0);
            if(!!v->c[0]->level)assert(v->c[0]->key< v->key);
            if(!!v->c[1]->level)assert(v->c[1]->key> v->key);
            chmax(ret,tour(v->c[1],print));
            return ret;
        }
        int tour(bool print=false){
            int ret=tour(root,print);
            if(print)cout<<endl;
            return 0;
        }
    };
}

typedef LL A;
typedef AA::tree B;
struct node{
    B b;
};
A mg(node& v,int key){
    return v.b.get(key);
}
A mg(A l,A r){
    return l+r;
}
namespace ST{
    node mem[1][512345];
    int cnt=0;
    node* get(){return mem[cnt++];}
}
struct seg_tree{
    int size;
    node *seg;
    void init(int l,int r,int k=0){
        auto &v=seg[k];
        v.b=B(true);
        if(r-l==1){
            //�t�̎��̏���
        }
        else if(r-l>1){
            int m=(l+r)/2;
            init(l,m,k*2+1);init(m,r,k*2+2);
        }
    }
    seg_tree(int n){
        size=1;
        while(size<n)size*=2;
        seg=ST::get();
        init(0,size);
    }
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
    A get(int a,int b,int k,int l,int r){
        if(a<=l){
            return mg(seg[k],b-1);
        }
        int m=(l+r)/2;
        bool ll=!(m<=a);
        bool rr=!(r<=a);
        A ret;
        if(ll&&rr)ret=mg(get(LQ),get(RQ));
        else if(ll)ret=get(LQ);
        else ret=get(RQ);
        return ret;
    }
    A get(int a,int b){return get(a,b,0,0,size);}
    void ins(int a,int b,int k,int l,int r,LL key,LL val){
        if(r<=a||b<=l)return;
        //cout<<"ins:"<<k<<" "<<key<<endl;
        seg[k].b.insert(key,val);
        //seg[k].b.tour(k==0);
        if(a<=l&&r<=b){

        }
        else{
            int m=(l+r)/2;
            ins(LQ,key,val);
            ins(RQ,key,val);
        }
    }
    void ins(int a,int b,LL val){
        ins(a,a+1,0,0,size,b-1,val);
    }
    void del(int a,int b,int k,int l,int r,LL key){
        if(r<=a||b<=l)return;
        //cout<<"del:"<<k<<" "<<key<<endl;
        seg[k].b.erase(key));
        //seg[k].b.tour(k==0);

        if(a<=l&&r<=b){

        }
        else{
            int m=(l+r)/2;
            del(LQ,key);
            del(RQ,key);
        }
    }
    void del(int a,int b){
        del(a,a+1,0,0,size,b-1);
    }

};

int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    vector<int> v(n);
    vector<set<int>> x(n);
    seg_tree seg(n+10);
    REP(i,n){
        int a;
        scanf("%d",&a);
        a--;
        v[i]=a;
        x[a].insert(i);
    }
    REP(i,n){
        int prv=-1;
        for(auto &now:x[i]){
            if(prv>=0){
                int len = now-prv;
                seg.ins(prv,now+1,len);
            }
            prv=now;
        }
    }

    REP(i,q){
        int type;
        scanf("%d",&type);
        //cout<<"query:"<<i<<" "<<AA::pool::stk.size<<endl;
        //cout<<"type:"<<type<<" ";

        if(type==2){
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%lld\n",seg.get(l-1,r));
        }
        else{
            int p,val;
            scanf("%d%d",&p,&val);
            p--;
            val--;
            //cout<<p<<" "<<val<<endl;
            if(v[p]==val)continue;
            {//erase
                auto& td=x[v[p]];
                {
                    auto ym=td.find(p);
                    if(ym!=td.begin()){
                        auto yb=ym;yb--;
                        //printf("q1 %d %d",*yb,(*ym)+1);cout<<endl;
                        seg.del(*yb,(*ym)+1);
                    }
                    {
                        auto ye=ym;ye++;
                        if(ye!=td.end()){
                            //cout<<"q2"<<endl;

                            seg.del(*ym,(*ye)+1);

                            if(ym!=td.begin()){
                                auto yb=ym;yb--;
                                //cout<<"q3"<<endl;
                                seg.ins(*yb,(*ye)+1,(*ye-(*yb)));

                            }
                        }
                    }
                }
                td.erase(p);
            }

            v[p]=val;
            {//insert
                auto& td=x[val];
                td.insert(p);
                {
                    auto ym=td.find(p);
                    if(ym!=td.begin()){
                        auto yb=ym;yb--;
                        seg.ins(*yb,(*ym)+1,*ym-*yb);
                    }
                    {
                        auto ye=ym;ye++;
                        if(ye!=td.end()){
                            if(ym!=td.begin()){
                                auto yb=ym;yb--;
                                seg.del(*yb,(*ye)+1);
                            }

                            seg.ins(*ym,(*ye)+1,*ye-*ym);
                        }
                    }
                }
            }
        }
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

#ifdef BTK
#define DEBUG if(1)
#else
#define DEBUG if(0)
#define CIN_ONLY if(0)
struct cww{cww(){
    CIN_ONLY{
        ios::sync_with_stdio(false);cin.tie(0);
    }
}}star;

#endif

#define fin "\n"
#define FOR(i,bg,ed) for(int i=(bg);i<(ed);i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(v) (v).begin(),(v).end()
#define fi first
#define se second
#define pb push_back
#define REC(ret, ...) std::function<ret (__VA_ARGS__)>
template <typename T>inline bool chmin(T &l,T r)
{bool a=l>r;if(a)l=r;return a;}
template <typename T>inline bool chmax(T &l,T r)
{bool a=l<r;if(a)l=r;return a;}
template <typename T>
istream& operator>>(istream &is,vector<T> &v){
    for(auto &it:v)is>>it;
    return is;
}

namespace AA{
    using Key = int;
    using Val = LL;
    constexpr int preffered_size = 2123456;
    struct node{
        int level,size;
        weak_ptr<node> par;
        shared_ptr<node> c[2];
        Key key,lb,ub;
        Val val,sum;
    };
    using link = shared_ptr<node>;
    using clink = const shared_ptr<node>;
        inline void update(const link v){
            //key
            v->size = v->c[0]->size + v->c[1]->size + !!v->level;
            v->lb   = v->c[0]->level ? v->c[0]->lb : v->key;
            v->ub   = v->c[1]->level ? v->c[1]->ub : v->key;
            //val
            v->sum = v->val;
            v->sum += v->c[0]->level ? v->c[0]->sum : 0;
            v->sum += v->c[1]->level ? v->c[1]->sum : 0;
        }

    //-memory pool--------------------------
    namespace pool{
        node mem[preffered_size];
        struct stack{
            node* stk[preffered_size];
            int size;
            stack(){
                size = 0;
                REP(i,preffered_size)
                    stk[i]=(mem+i);
            }
            inline node* const pop(){
                return stk[size++];
            }
            inline void push(node* const p){
                stk[--size]=p;
            }
        }stk;
        inline node* const allocater(){
            return stk.pop();
        }
        inline void deleter(node* const p){
            stk.push(p);
        }
        inline link get(){
            return move(link(allocater(),deleter));
        }
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    inline const link leaf(const link lf = pool::get()){
        lf->level = 0;
        lf->size = 0;
        lf->c[0] = nullptr;
        lf->c[1] = nullptr;
        return move(lf);
    }
    inline bool isleaf(const link x){
        return !x->level;
    }
    inline const link assign(const link v,Key key,Val val){
        v->level = 1;
        v->key   = v->lb = v->ub = key;
        v->val   = val;
        v->c[0]  = leaf();v->c[0]->par = v;
        v->c[1]  = leaf();v->c[1]->par = v;
        update(v);
        return move(v);
    }

    struct tree{
        link root;
        inline const link skew(const link v){
            const link l = v->c[0];
            if(v->level == l->level){
                v->c[0] = l->c[1];
                l->c[1] = v;
                v->c[0]->par = v;
                l->par = v->par;
                v->par = l;
                if(!l->par.expired()){
                    const link p = l->par.lock();
                    p->c[p->key < l->key] = l;
                }
                update(v);
                update(l);
                return move(l);
            }
            else{
                update(v);
                return move(v);
            }
        }
        inline const link split(const link v){
            const link r  = v->c[1];
            const link rr = r->c[1];
            if(v->level == r->level
               && v->level == rr->level){
                v->c[1] = r->c[0];
                r->c[0] = v;
                v->c[1]->par = v;
                r->par = v->par;
                v->par = r;
                r->level ++;
                if(!r->par.expired()){
                    const link p = r->par.lock();
                    p->c[p->key < r->key] = r;
                }
                update(v);
                update(r);
                return move(r);
            }
            else{
                update(v);
                return move(v);
            }
        }
        inline const link modify(const link v){
            int level = min(v->c[0]->level,v->c[1]->level) + 1;
            chmin(v->level,level) && chmin(v->c[1]->level,level);
            return move(v);
        }

        inline bool insert(Key key,Val val){
            link v = root;
            while(v->level){
                if(v->key == key){
                    v->val = val;
                    return false;
                }
                v = v->c[v->key < key];
            }

            v = assign(move(v),key,val);

            while(!v->par.expired()){
                v = v->par.lock();
                v = skew(move(v));
                v = split(move(v));
            }
            root = v;
            return true;
        }

        inline bool erase(Key key){
            link v = root;
            while(!v->level||v->key!=key){
                if(!v->level)return false;
                v = v->c[v->key < key];
            }
            assert(v->key==key);
            while(v->level){
                const link u = v->c[!v->c[0]->level];
                v->key = u->key;
                v->val = u->val;
                v = u;
            }

            v = v->par.lock();
            v = leaf(move(v));

            while(!v->par.expired()){
                v = v->par.lock();
                v = modify(move(v));
                v = skew(move(v));
                link r = v->c[1];
                if(r->level){
                    r = skew(move(r));
                    const link rr = r->c[1];
                    if(rr->level){
                        skew(move(rr));
                    }
                }
                v = split(move(v));
                r = v->c[1];
                if(r->level){
                    split(move(r));
                }
            }
            root = v;
            return true;
        }
        inline Val get(Key b){
            link v = root;
            Val ret = 0;
            while(!isleaf(v)&& b >= v->lb){
                if(v->key <= b){
                    ret += v->val;
                    if(!isleaf(v->c[0]))ret += v->c[0]->sum;
                    v = v->c[1];
                }
                else{
                    v = v->c[0];
                }
            }
            return ret;
        }
        tree(){
            root = leaf();
        }
    };
}

typedef LL A;
typedef AA::tree B;
struct node{
    B b;
};
A mg(node& v,int key){
    return v.b.get(key);
}
A mg(A l,A r){
    return l+r;
}
namespace ST{
    node mem[1][512345];
    int cnt=0;
    node* get(){return mem[cnt++];}
}
struct seg_tree{
    int size;
    node *seg;
    void init(int l,int r,int k=0){
        auto &v=seg[k];
        v.b=B();
        if(r-l==1){
            //�t�̎��̏���
        }
        else if(r-l>1){
            int m=(l+r)/2;
            init(l,m,k*2+1);init(m,r,k*2+2);
        }
    }
    seg_tree(int n){
        size=1;
        while(size<n)size*=2;
        seg=ST::get();
        init(0,size);
    }
#define LQ a,b,k*2+1,l,m
#define RQ a,b,k*2+2,m,r
    A get(int a,int b,int k,int l,int r){
        if(a<=l){
            return mg(seg[k],b-1);
        }
        int m=(l+r)/2;
        bool ll=!(m<=a);
        bool rr=!(r<=a);
        A ret;
        if(ll&&rr)ret=mg(get(LQ),get(RQ));
        else if(ll)ret=get(LQ);
        else ret=get(RQ);
        return ret;
    }
    A get(int a,int b){return get(a,b,0,0,size);}
    void ins(int a,int b,int k,int l,int r,LL key,LL val){
        if(r<=a||b<=l)return;
        seg[k].b.insert(key,val);
        if(a<=l&&r<=b){

        }
        else{
            int m=(l+r)/2;
            ins(LQ,key,val);
            ins(RQ,key,val);
        }
    }
    void ins(int a,int b,LL val){
        ins(a,a+1,0,0,size,b-1,val);
    }
    void del(int a,int b,int k,int l,int r,LL key){
        if(r<=a||b<=l)return;
        seg[k].b.erase(key);
        if(a<=l&&r<=b){

        }
        else{
            int m=(l+r)/2;
            del(LQ,key);
            del(RQ,key);
        }
    }
    void del(int a,int b){
        del(a,a+1,0,0,size,b-1);
    }

};

int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    vector<int> v(n);
    vector<set<int>> x(n);
    seg_tree seg(n+10);
    REP(i,n){
        int a;
        scanf("%d",&a);
        a--;
        v[i]=a;
        x[a].insert(i);
    }
    REP(i,n){
        int prv=-1;
        for(auto &now:x[i]){
            if(prv>=0){
                int len = now-prv;
                seg.ins(prv,now+1,len);
            }
            prv=now;
        }
    }

    REP(i,q){
        int type;
        scanf("%d",&type);
        if(type==2){
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%lld\n",seg.get(l-1,r));
        }
        else{
            int p,val;
            scanf("%d%d",&p,&val);
            p--;
            val--;
            if(v[p]==val)continue;
            {//erase
                auto& td=x[v[p]];
                {
                    auto ym=td.find(p);
                    if(ym!=td.begin()){
                        auto yb=ym;yb--;
                        seg.del(*yb,(*ym)+1);
                    }
                    {
                        auto ye=ym;ye++;
                        if(ye!=td.end()){
                            seg.del(*ym,(*ye)+1);

                            if(ym!=td.begin()){
                                auto yb=ym;yb--;
                                seg.ins(*yb,(*ye)+1,(*ye-(*yb)));

                            }
                        }
                    }
                }
                td.erase(p);
            }

            v[p]=val;
            {//insert
                auto& td=x[val];
                td.insert(p);
                {
                    auto ym=td.find(p);
                    if(ym!=td.begin()){
                        auto yb=ym;yb--;
                        seg.ins(*yb,(*ym)+1,*ym-*yb);
                    }
                    {
                        auto ye=ym;ye++;
                        if(ye!=td.end()){

                            if(ym!=td.begin()){
                                auto yb=ym;yb--;
                                seg.del(*yb,(*ye)+1);
                            }

                            seg.ins(*ym,(*ye)+1,*ye-*ym);
                        }
                    }
                }
            }
        }
    }
    return 0;
}


#include <bits/stdc++.h>
#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")
#define ll long long
using namespace std;
inline int read()
{int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int a[100005],vis[100005],l[100005],r[100005],n,m,pos,x,opt,li,ri;
int main (){
	int i,j;ll ans=0;
	n=read();m=read();
	for (i=1;i<=n;i++)
	{a[i]=read();}
	for (i=1;i<=m;i++)
	{opt=read();
	if (opt==1)
	{pos=read();x=read();
	a[pos]=x;continue;
	}
	ans=0;
	li=read();ri=read();
	for(j=li;j<=ri;r[*(a+j)]=j++);for(j=ri;j>=li;l[*(a+j)]=j--);
	for(j=li;j<=ri;vis[a[j++]]=i)ans+=((vis[a[j]]<i)*(r[a[j]]-l[a[j]]));
	printf ("%lld\n",ans);
	}
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
/* 2-D segment tree
   find the sum of (i-prev[i])
   for all l<=i<=r && l<=prev[i]<=r
*/
inline int read()
{int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int n,m,las[100005],pre[100005];
int a[100005],b[100005],t[100005],d[100005];
int lc[16000005],rc[16000005],cnt=0;
ll s[16000005];
void modify(int &pos,int l,int r,int p,int del)
{if (!pos) pos=++cnt;
if (l==r) {s[pos]+=del;return;}
int mid=(l+r)>>1;
if (p<=mid) modify(lc[pos],l,mid,p,del);
else modify(rc[pos],mid+1,r,p,del);
s[pos]=s[lc[pos]]+s[rc[pos]];
}
ll query(int pos,int l,int r,int lp,int rp)
{if (!pos) return 0;
if (l==lp&&r==rp) return s[pos];
int mid=(l+r)>>1;
if (rp<=mid) return query(lc[pos],l,mid,lp,rp);
if (lp>mid) return query(rc[pos],mid+1,r,lp,rp);
return query(lc[pos],l,mid,lp,mid)+query(rc[pos],mid+1,r,mid+1,rp);
}
inline int gpre(int p,int pos)
{int l=1,r=pos-1;
int kil=query(d[p],1,n,1,pos)-1;
if (kil==0) return 0;
while (l<=r)
{int mid=(l+r)>>1;
if (query(d[p],1,n,1,mid)<kil) {l=mid+1;}
else {r=mid-1;}
}
return l;
}
inline int gnxt(int p,int pos)
{int l=pos+1,r=n;
int kil=query(d[p],1,n,1,pos)+1;
if (kil==query(d[p],1,n,1,n)+1) return n+1;
while (l<=r)
{int mid=(l+r)>>1;
if (query(d[p],1,n,1,mid)>=kil) {r=mid-1;}
else {l=mid+1;}
}
return l;
}
inline void add(int d1,int d2,int del)
{if (!d2) return;
while (d1<=n) {modify(t[d1],1,n,d2,del);d1+=(d1&(-d1));}
}
inline ll ask(int p,int l,int r)
{ll s=0;
while (p) {s+=query(t[p],1,n,l,r);p-=(p&(-p));}
return s;
}
inline ll ask(int l,int r)
{return ask(r,l,r)-ask(l-1,l,r);}
int main (){
	int i,opt,l,r;
	n=read();m=read();
	for (i=1;i<=n;i++)
	{a[i]=read();
	pre[i]=las[a[i]];
	las[a[i]]=i;
	add(i,pre[i],i-pre[i]);
	modify(d[a[i]],1,n,i,1);
	}
	while (m--)
	{opt=read();l=read();r=read();
	if (opt==2) {printf ("%lld\n",ask(l,r));continue;}
	int pri=gpre(a[l],l),nxt=gnxt(a[l],l);
	modify(d[a[l]],1,n,l,-1);
	add(l,pri,pri-l);
	add(nxt,l,l-nxt);
	add(nxt,pri,nxt-pri);
	a[l]=r;modify(d[a[l]],1,n,l,1);
	pri=gpre(a[l],l);nxt=gnxt(a[l],l);
	add(l,pri,l-pri);
	add(nxt,l,nxt-l);
	add(nxt,pri,pri-nxt);
	}
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
/* 2-D segment tree
   find the sum of (i-prev[i])
   for all l<=i<=r && l<=prev[i]<=r
*/
inline int read()
{int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int n,m,las[100005],pre[100005];
int a[100005],b[100005],t[100005],d[100005];
int lc[16000005],rc[16000005],cnt=0;
ll s[16000005];
void modify(int &pos,int l,int r,int p,int del)
{if (!pos) pos=++cnt;
if (l==r) {s[pos]+=del;return;}
int mid=(l+r)>>1;
if (p<=mid) modify(lc[pos],l,mid,p,del);
else modify(rc[pos],mid+1,r,p,del);
s[pos]=s[lc[pos]]+s[rc[pos]];
}
ll query(int pos,int l,int r,int lp,int rp)
{if (!pos) return 0;
if (l==lp&&r==rp) return s[pos];
int mid=(l+r)>>1;
if (rp<=mid) return query(lc[pos],l,mid,lp,rp);
if (lp>mid) return query(rc[pos],mid+1,r,lp,rp);
return query(lc[pos],l,mid,lp,mid)+query(rc[pos],mid+1,r,mid+1,rp);
}
inline int gpre(int p,int pos)
{int l=1,r=pos-1;
int kil=query(d[p],1,n,1,pos)-1;
if (kil==0) return 0;
while (l<=r)
{int mid=(l+r)>>1;
if (query(d[p],1,n,1,mid)<kil) {l=mid+1;}
else {r=mid-1;}
}
return l;
}
inline int gnxt(int p,int pos)
{int l=pos+1,r=n;
int kil=query(d[p],1,n,1,pos)+1;
if (kil==query(d[p],1,n,1,n)+1) return n+1;
while (l<=r)
{int mid=(l+r)>>1;
if (query(d[p],1,n,1,mid)>=kil) {r=mid-1;}
else {l=mid+1;}
}
return l;
}
inline void add(int d1,int d2,int del)
{if (!d2) return;
while (d1<=n) {modify(t[d1],1,n,d2,del);d1+=(d1&(-d1));}
}
inline ll ask(int p,int l,int r)
{ll s=0;
while (p) {s+=query(t[p],1,n,l,r);p-=(p&(-p));}
return s;
}
inline ll ask(int l,int r)
{return ask(r,l,r)-ask(l-1,l,r);}
int main (){
	int i,opt,l,r;
	n=read();m=read();
	for (i=1;i<=n;i++)
	{a[i]=read();
	pre[i]=las[a[i]];
	las[a[i]]=i;
	add(i,pre[i],i-pre[i]);
	modify(d[a[i]],1,n,i,1);
	}
	while (m--)
	{opt=read();l=read();r=read();
	if (opt==2) {printf ("%lld\n",ask(l,r));continue;}
	int pri=gpre(a[l],l),nxt=gnxt(a[l],l);
	cerr<<pri<<' '<<nxt<<endl;
	modify(d[a[l]],1,n,l,-1);
	add(l,pri,pri-l);
	add(nxt,l,l-nxt);
	add(nxt,pri,nxt-pri);
	a[l]=r;modify(d[a[l]],1,n,l,1);
	pri=gpre(a[l],l);nxt=gnxt(a[l],l);
	add(l,pri,l-pri);
	add(nxt,l,nxt-l);
	add(nxt,pri,pri-nxt);
	}
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int a[100005],vis[100005],l[100005],r[100005],n,m,pos,x,opt,li,ri;
int main (){
	int i,j;ll ans=0;
	n=read();m=read();
	for (i=1;i<=n;i++)
	{a[i]=read();}
	for (i=1;i<=m;i++)
	{opt=read();
	if (opt==1)
	{pos=read();x=read();
	a[pos]=x;continue;
	}
	ans=0;
	li=read();ri=read();
	for (j=li;j<=ri;r[*(a+j)]=j++);
	for (j=ri;j>=li;l[*(a+j)]=j--);
	for (j=li;j<=ri;j++)
	{if (vis[a[j]]<i) {ans+=r[a[j]]-l[a[j]];vis[a[j]]=i;}
	}
	printf ("%lld\n",ans);
	}
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int a[100005],t[100005],num[100005],l[100005],n,m,pos,x,opt,li,ri;
set <int> s[100005];
set <int>::iterator it;
int main (){
	int i,j;ll ans=0;
	n=read();m=read();
	for (i=1;i<=n;i++)
	{a[i]=read();
	l[i]=t[a[i]];
	num[i]=(t[a[i]]?i-t[a[i]]:0);
	t[a[i]]=i;s[a[i]].insert(i);
	}
	for (i=1;i<=m;i++)
	{opt=read();
	if (opt==1)
	{pos=read();x=read();
	it=s[a[pos]].upper_bound(pos);
	if (it!=s[a[pos]].end())
	{int ps=(*it);it--;
	if (it!=s[a[pos]].begin())
	{it--;l[ps]=(*it);num[ps]=ps-l[ps];}
	}
	s[a[pos]].erase(s[a[pos]].lower_bound(pos));
	a[pos]=x;
	it=s[x].upper_bound(pos);
	if (it!=s[x].begin())
	{it--;l[pos]=(*it);num[pos]=pos-l[pos];}
	else {l[pos]=0;num[pos]=0;}
	s[x].insert(pos);
	}
	ans=0;
	li=read();ri=read();
	for(j=li;j<=ri;ans+=(l[j]>=li?num[j]:0));
	printf ("%lld\n",ans);
	}
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int a[100005],vis[100005],l[100005],r[100005],n,m,pos,x,opt,li,ri;
int main (){
	int i,j;ll ans=0;
	n=read();m=read();
	for (i=1;i<=n;i++)
	{a[i]=read();}
	for (i=1;i<=m;i++)
	{opt=read();
	if (opt==1)
	{pos=read();x=read();
	a[pos]=x;continue;
	}
	ans=0;
	li=read();ri=read();
	for(j=li;j<=ri;r[*(a+j)]=j++);for(j=ri;j>=li;l[*(a+j)]=j--);
	for(j=li;j<=ri;vis[a[j++]]=i)ans+=((vis[a[j]]<i)*(r[a[j]]-l[a[j]]));
	printf ("%lld\n",ans);
	}
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int a[100005],vis[100005],l[100005],r[100005],n,m,pos,x,opt,li,ri;
int main (){
	int i,j;ll ans=0;
	n=read();m=read();
	for (i=1;i<=n;i++)
	{a[i]=read();}
	for (i=1;i<=m;i++)
	{opt=read();
	if (opt==1)
	{pos=read();
	x=read();
	a[pos]=x;
	continue;
	}
	ans=0;
	li=read();ri=read();
	for (j=li;j<=ri;j++) r[a[j]]=j;
	for (j=ri;j>=li;j--) l[a[j]]=j;
	for (j=li;j<=ri;j++) ans+=(vis[a[j]]<i?(r[a[j]]-l[a[j]]):0),vis[a[j]]=i;
	printf ("%lld\n",ans);
	}
	return 0;
}


#include <bits/stdc++.h>
#define MOD 1000000007LL
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

struct BITree{
	vector<ll> sum;
	int n;
	BITree(){}
	void init(int nn){
		n=nn;
		for(int i=0;i<=n;i++){
			sum.push_back(0LL);
		}
	}
	ll query(int k){
		ll res=0;
		while(k>0){
			res+=sum[k];
			k-=k&-k;
		}
		return res;
	}
	void add(int k,ll x){
		while(k<=n){
			sum[k]+=x;
			k+=k&-k;
		}
	}
};

struct segtree{
	vector<BITree> bit;
	static const int n=(1<<17);
	vector<int> ids[1<<18];

	segtree(){}
	void init(){
		for(int i=0;i<n*2-1;i++){
			bit.push_back(BITree());
		}
		for(int i=n-1;i<n*2-1;i++){
			ids[i].push_back(-1);
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
		for(int i=n-2;i>=0;i--){
			for(int j=0;j<ids[i*2+1].size();j++){
				ids[i].push_back(ids[i*2+1][j]);
			}
			for(int j=0;j<ids[i*2+2].size();j++){
				ids[i].push_back(ids[i*2+2][j]);
			}
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
	}
	void addnode(int k,int val){
		k+=n-1;
		ids[k].push_back(val);
	}

	void add(int f,int t,int val){
		int k=f+n-1;
		int pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
		bit[k].add(pos,val);
		while(k>0){
			k=(k-1)/2;
			pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
			bit[k].add(pos,val);
		}
	}
	ll query(int a,int b,int k=0,int l=0,int r=n){
		if(b<=l || r<=a)return 0;
		if(a<=l && r<=b){
			int lef=lower_bound(ids[k].begin(),ids[k].end(),a)-ids[k].begin();
			int rig=lower_bound(ids[k].begin(),ids[k].end(),b)-ids[k].begin();
			return bit[k].query(rig-1)-bit[k].query(lef-1);
		}
		ll vl=query(a,b,k*2+1,l,(l+r)/2);
		ll vr=query(a,b,k*2+2,(l+r)/2,r);
		return vl+vr;
	}
};

segtree seg;

int n,m;
int a[100001];
int tmp[100001];
set<int> now[100001];
int typ[100001],p[10001],val[100001];

int main(void){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
		a[i]--;
		now[a[i]].insert(i);
		tmp[i]=a[i];
	}
	for(int i=0;i<n;i++){
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.addnode(i,*it);
		}
	}
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&typ[i],&p[i],&val[i]);
		p[i]--;
		if(typ[i]==1){
			val[i]--;
			int prev=a[p[i]];
			if(prev==val[i])continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end() && it!=now[prev].begin()){
				it--;
				int f=*it;
				it++;
				seg.addnode(f,*it);
			}
			a[p[i]]=val[i];
			int next=a[p[i]];
			it=now[next].upper_bound(p[i]);
			if(it!=now[next].end()){
				seg.addnode(p[i],*it);
			}
			if(it!=now[next].begin()){
				it--;
				seg.addnode(*it,p[i]);
			}
			now[next].insert(p[i]);
		}
	}
	seg.init();
	for(int i=0;i<n;i++){
		now[i].clear();
		a[i]=tmp[i];
	}
	for(int i=n-1;i>=0;i--){
		now[a[i]].insert(i);
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.add(i,*it,(*it)-i);
		}
	}
	for(int i=0;i<m;i++){
		if(m==100000)printf(" %d\n",typ[i]);
		if(typ[i]==1){
			int prev=a[p[i]];
			if(val[i]==prev)continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end()){
				int va=*it;
				seg.add(p[i],va,p[i]-va);
				if(it!=now[prev].begin()){
					it--;
					seg.add(*it,p[i],(*it)-p[i]);
					seg.add(*it,va,va-(*it));
				}
			}else if(it!=now[prev].begin()){
				it--;
				seg.add(*it,p[i],(*it)-p[i]);
			}

			it=now[val[i]].upper_bound(p[i]);
			if(it!=now[val[i]].end()){
				seg.add(p[i],*it,(*it)-p[i]);
				if(it!=now[val[i]].begin()){
					int np=*it;
					it--;
					seg.add(*it,np,(*it)-np);
					seg.add(*it,p[i],p[i]-(*it));
				}
			}else if(it!=now[val[i]].begin()){
				it--;
				seg.add(*it,p[i],p[i]-(*it));
			}
			now[val[i]].insert(p[i]);
			a[p[i]]=val[i];
		}else{
			printf("%lld\n",seg.query(p[i],val[i]));
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define MOD 1000000007LL
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

struct BITree{
	vector<ll> sum;
	int n;
	BITree(){}
	void init(int nn){
		n=nn;
		for(int i=0;i<=n;i++){
			sum.push_back(0LL);
		}
	}
	ll query(int k){
		ll res=0;
		while(k>0){
			res+=sum[k];
			k-=k&-k;
		}
		return res;
	}
	void add(int k,ll x){
		while(k<=n){
			sum[k]+=x;
			k+=k&-k;
		}
	}
};

struct segtree{
	vector<BITree> bit;
	static const int n=(1<<17);
	vector<int> ids[1<<18];

	segtree(){}
	void init(){
		for(int i=0;i<n*2-1;i++){
			bit.push_back(BITree());
		}
		for(int i=n-1;i<n*2-1;i++){
			ids[i].push_back(-1);
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
		for(int i=n-2;i>=0;i--){
			for(int j=0;j<ids[i*2+1].size();j++){
				ids[i].push_back(ids[i*2+1][j]);
			}
			for(int j=0;j<ids[i*2+2].size();j++){
				ids[i].push_back(ids[i*2+2][j]);
			}
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
	}
	void addnode(int k,int val){
		k+=n-1;
		ids[k].push_back(val);
	}

	void add(int f,int t,int val){
		int k=f+n-1;
		int pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
		bit[k].add(pos,val);
		while(k>0){
			k=(k-1)/2;
			pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
			bit[k].add(pos,val);
		}
	}
	ll query(int a,int b,int k=0,int l=0,int r=n){
		if(b<=l || r<=a)return 0;
		if(a<=l && r<=b){
			int lef=lower_bound(ids[k].begin(),ids[k].end(),a)-ids[k].begin();
			int rig=lower_bound(ids[k].begin(),ids[k].end(),b)-ids[k].begin();
			return bit[k].query(rig-1)-bit[k].query(lef-1);
		}
		ll vl=query(a,b,k*2+1,l,(l+r)/2);
		ll vr=query(a,b,k*2+2,(l+r)/2,r);
		return vl+vr;
	}
};

segtree seg;

int n,m;
int a[100001];
int tmp[100001];
set<int> now[100001];
int typ[100001],p[100001],val[100001];

int main(void){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
		a[i]--;
		now[a[i]].insert(i);
		tmp[i]=a[i];
	}
	for(int i=0;i<n;i++){
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.addnode(i,*it);
		}
	}
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&typ[i],&p[i],&val[i]);
		p[i]--;
		if(typ[i]==1){
			val[i]--;
			int prev=a[p[i]];
			if(prev==val[i])continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end() && it!=now[prev].begin()){
				it--;
				int f=*it;
				it++;
				seg.addnode(f,*it);
			}
			a[p[i]]=val[i];
			int next=a[p[i]];
			it=now[next].upper_bound(p[i]);
			if(it!=now[next].end()){
				seg.addnode(p[i],*it);
			}
			if(it!=now[next].begin()){
				it--;
				seg.addnode(*it,p[i]);
			}
			now[next].insert(p[i]);
		}
	}
	seg.init();
	for(int i=0;i<n;i++){
		now[i].clear();
		a[i]=tmp[i];
	}
	for(int i=n-1;i>=0;i--){
		now[a[i]].insert(i);
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.add(i,*it,(*it)-i);
		}
	}
	for(int i=0;i<m;i++){
		if(typ[i]==1){
			int prev=a[p[i]];
			if(val[i]==prev)continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end()){
				int va=*it;
				seg.add(p[i],va,p[i]-va);
				if(it!=now[prev].begin()){
					it--;
					seg.add(*it,p[i],(*it)-p[i]);
					seg.add(*it,va,va-(*it));
				}
			}else if(it!=now[prev].begin()){
				it--;
				seg.add(*it,p[i],(*it)-p[i]);
			}

			it=now[val[i]].upper_bound(p[i]);
			if(it!=now[val[i]].end()){
				seg.add(p[i],*it,(*it)-p[i]);
				if(it!=now[val[i]].begin()){
					int np=*it;
					it--;
					seg.add(*it,np,(*it)-np);
					seg.add(*it,p[i],p[i]-(*it));
				}
			}else if(it!=now[val[i]].begin()){
				it--;
				seg.add(*it,p[i],p[i]-(*it));
			}
			now[val[i]].insert(p[i]);
			a[p[i]]=val[i];
		}else{
			printf("%lld\n",seg.query(p[i],val[i]));
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define MOD 1000000007LL
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

struct BITree{
	vector<ll> sum;
	int n;
	BITree(){}
	void init(int nn){
		n=nn;
		for(int i=0;i<=n;i++){
			sum.push_back(0LL);
		}
	}
	ll query(int k){
		ll res=0;
		while(k>0){
			res+=sum[k];
			k-=k&-k;
		}
		return res;
	}
	void add(int k,ll x){
		while(k<=n){
			sum[k]+=x;
			k+=k&-k;
		}
	}
};

struct segtree{
	vector<BITree> bit;
	static const int n=(1<<17);
	vector<int> ids[1<<18];

	segtree(){}
	void init(){
		for(int i=0;i<n*2-1;i++){
			bit.push_back(BITree());
		}
		for(int i=n-1;i<n*2-1;i++){
			ids[i].push_back(-1);
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
		for(int i=n-2;i>=0;i--){
			for(int j=0;j<ids[i*2+1].size();j++){
				ids[i].push_back(ids[i*2+1][j]);
			}
			for(int j=0;j<ids[i*2+2].size();j++){
				ids[i].push_back(ids[i*2+2][j]);
			}
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
	}
	void addnode(int k,int val){
		k+=n-1;
		ids[k].push_back(val);
	}

	void add(int f,int t,int val){
		int k=f+n-1;
		int pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
		bit[k].add(pos,val);
		while(k>0){
			k=(k-1)/2;
			pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
			bit[k].add(pos,val);
		}
	}
	ll query(int a,int b,int k=0,int l=0,int r=n){
		if(b<=l || r<=a)return 0;
		if(a<=l && r<=b){
			int lef=lower_bound(ids[k].begin(),ids[k].end(),a)-ids[k].begin();
			int rig=lower_bound(ids[k].begin(),ids[k].end(),b)-ids[k].begin();
			return bit[k].query(rig-1)-bit[k].query(lef-1);
		}
		ll vl=query(a,b,k*2+1,l,(l+r)/2);
		ll vr=query(a,b,k*2+2,(l+r)/2,r);
		return vl+vr;
	}
};

segtree seg;

int n,m;
int a[100001];
int tmp[100001];
set<int> now[100001];
int t[100001],p[10001],val[100001];

int main(void){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
		a[i]--;
		now[a[i]].insert(i);
		tmp[i]=a[i];
	}
	for(int i=0;i<n;i++){
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.addnode(i,*it);
		}
	}
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&t[i],&p[i],&val[i]);
		p[i]--;
		if(t[i]==1){
			val[i]--;
			int prev=a[p[i]];
			if(prev==val[i])continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end() && it!=now[prev].begin()){
				it--;
				int f=*it;
				it++;
				seg.addnode(f,*it);
			}
			a[p[i]]=val[i];
			int next=a[p[i]];
			it=now[next].upper_bound(p[i]);
			if(it!=now[next].end()){
				seg.addnode(p[i],*it);
			}
			if(it!=now[next].begin()){
				it--;
				seg.addnode(*it,p[i]);
			}
			now[next].insert(p[i]);
		}
	}
	seg.init();
	for(int i=0;i<n;i++){
		now[i].clear();
		a[i]=tmp[i];
	}
	for(int i=n-1;i>=0;i--){
		now[a[i]].insert(i);
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.add(i,*it,(*it)-i);
		}
	}
	for(int i=0;i<m;i++){
		if(m==100000)printf("%d %d %d\n",t[i],p[i],val[i]);
		if(t[i]==1){
			int prev=a[p[i]];
			if(val[i]==prev)continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end()){
				int va=*it;
				seg.add(p[i],va,p[i]-va);
				if(it!=now[prev].begin()){
					it--;
					seg.add(*it,p[i],(*it)-p[i]);
					seg.add(*it,va,va-(*it));
				}
			}else if(it!=now[prev].begin()){
				it--;
				seg.add(*it,p[i],(*it)-p[i]);
			}

			it=now[val[i]].upper_bound(p[i]);
			if(it!=now[val[i]].end()){
				seg.add(p[i],*it,(*it)-p[i]);
				if(it!=now[val[i]].begin()){
					int np=*it;
					it--;
					seg.add(*it,np,(*it)-np);
					seg.add(*it,p[i],p[i]-(*it));
				}
			}else if(it!=now[val[i]].begin()){
				it--;
				seg.add(*it,p[i],p[i]-(*it));
			}
			now[val[i]].insert(p[i]);
			a[p[i]]=val[i];
		}else{
			printf("%lld\n",seg.query(p[i],val[i]));
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define MOD 1000000007LL
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

struct BITree{
	vector<ll> sum;
	int n;
	BITree(){}
	void init(int nn){
		n=nn;
		for(int i=0;i<=n;i++){
			sum.push_back(0LL);
		}
	}
	ll query(int k){
		ll res=0;
		while(k>0){
			res+=sum[k];
			k-=k&-k;
		}
		return res;
	}
	void add(int k,ll x){
		while(k<=n){
			sum[k]+=x;
			k+=k&-k;
		}
	}
};

struct segtree{
	vector<BITree> bit;
	static const int n=(1<<17);
	vector<int> ids[1<<18];

	segtree(){}
	void init(){
		for(int i=0;i<n*2-1;i++){
			bit.push_back(BITree());
		}
		for(int i=n-1;i<n*2-1;i++){
			ids[i].push_back(-1);
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
		for(int i=n-2;i>=0;i--){
			for(int j=0;j<ids[i*2+1].size();j++){
				ids[i].push_back(ids[i*2+1][j]);
			}
			for(int j=0;j<ids[i*2+2].size();j++){
				ids[i].push_back(ids[i*2+2][j]);
			}
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
	}
	void addnode(int k,int val){
		k+=n-1;
		ids[k].push_back(val);
	}

	void add(int f,int t,int val){
		int k=f+n-1;
		int pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
		bit[k].add(pos,val);
		while(k>0){
			k=(k-1)/2;
			pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
			bit[k].add(pos,val);
		}
	}
	ll query(int a,int b,int k=0,int l=0,int r=n){
		if(b<=l || r<=a)return 0;
		if(a<=l && r<=b){
			int lef=lower_bound(ids[k].begin(),ids[k].end(),a)-ids[k].begin();
			int rig=lower_bound(ids[k].begin(),ids[k].end(),b)-ids[k].begin();
			return bit[k].query(rig-1)-bit[k].query(lef-1);
		}
		ll vl=query(a,b,k*2+1,l,(l+r)/2);
		ll vr=query(a,b,k*2+2,(l+r)/2,r);
		return vl+vr;
	}
};

segtree seg;

int n,m;
int a[100001];
int tmp[100001];
set<int> now[100001];
int t[100001],p[10001],val[100001];

int main(void){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
		a[i]--;
		now[a[i]].insert(i);
		tmp[i]=a[i];
	}
	for(int i=0;i<n;i++){
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.addnode(i,*it);
		}
	}
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&t[i],&p[i],&val[i]);
		p[i]--;
		if(t[i]==1){
			val[i]--;
			int prev=a[p[i]];
			if(prev==val[i])continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end() && it!=now[prev].begin()){
				it--;
				int f=*it;
				it++;
				seg.addnode(f,*it);
			}
			a[p[i]]=val[i];
			int next=a[p[i]];
			it=now[next].upper_bound(p[i]);
			if(it!=now[next].end()){
				seg.addnode(p[i],*it);
			}
			if(it!=now[next].begin()){
				it--;
				seg.addnode(*it,p[i]);
			}
			now[next].insert(p[i]);
		}
	}
	seg.init();
	for(int i=0;i<n;i++){
		now[i].clear();
		a[i]=tmp[i];
	}
	for(int i=n-1;i>=0;i--){
		now[a[i]].insert(i);
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.add(i,*it,(*it)-i);
		}
	}
	for(int i=0;i<m;i++){
		if(t[i]==1){
			int prev=a[p[i]];
			if(val[i]==prev)continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end()){
				int va=*it;
				seg.add(p[i],va,p[i]-va);
				if(it!=now[prev].begin()){
					it--;
					seg.add(*it,p[i],(*it)-p[i]);
					seg.add(*it,va,va-(*it));
				}
			}else if(it!=now[prev].begin()){
				it--;
				seg.add(*it,p[i],(*it)-p[i]);
			}

			it=now[val[i]].upper_bound(p[i]);
			if(it!=now[val[i]].end()){
				seg.add(p[i],*it,(*it)-p[i]);
				if(it!=now[val[i]].begin()){
					int np=*it;
					it--;
					seg.add(*it,np,(*it)-np);
					seg.add(*it,p[i],p[i]-(*it));
				}
			}else if(it!=now[val[i]].begin()){
				it--;
				seg.add(*it,p[i],p[i]-(*it));
			}
			now[val[i]].insert(p[i]);
			a[p[i]]=val[i];
		}else{
			printf("%lld\n",seg.query(p[i],val[i]));
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define MOD 1000000007LL
using namespace std;
typedef long long ll;
typedef pair<int,int> P;

struct BITree{
	vector<ll> sum;
	int n;
	BITree(){}
	void init(int nn){
		n=nn;
		for(int i=0;i<=n;i++){
			sum.push_back(0LL);
		}
	}
	ll query(int k){
		ll res=0;
		while(k>0){
			res+=sum[k];
			k-=k&-k;
		}
		return res;
	}
	void add(int k,ll x){
		while(k<=n){
			sum[k]+=x;
			k+=k&-k;
		}
	}
};

struct segtree{
	vector<BITree> bit;
	static const int n=(1<<17);
	vector<int> ids[1<<18];

	segtree(){}
	void init(){
		for(int i=0;i<n*2-1;i++){
			bit.push_back(BITree());
		}
		for(int i=n-1;i<n*2-1;i++){
			ids[i].push_back(-1);
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
		for(int i=n-2;i>=0;i--){
			for(int j=0;j<ids[i*2+1].size();j++){
				ids[i].push_back(ids[i*2+1][j]);
			}
			for(int j=0;j<ids[i*2+2].size();j++){
				ids[i].push_back(ids[i*2+2][j]);
			}
			sort(ids[i].begin(),ids[i].end());
			ids[i].erase(unique(ids[i].begin(),ids[i].end()),ids[i].end());
			bit[i].init(ids[i].size());
		}
	}
	void addnode(int k,int val){
		k+=n-1;
		ids[k].push_back(val);
	}

	void add(int f,int t,int val){
		int k=f+n-1;
		int pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
		bit[k].add(pos,val);
		while(k>0){
			k=(k-1)/2;
			pos=lower_bound(ids[k].begin(),ids[k].end(),t)-ids[k].begin();
			bit[k].add(pos,val);
		}
	}
	ll query(int a,int b,int k=0,int l=0,int r=n){
		if(b<=l || r<=a)return 0;
		if(a<=l && r<=b){
			int lef=lower_bound(ids[k].begin(),ids[k].end(),a)-ids[k].begin();
			int rig=lower_bound(ids[k].begin(),ids[k].end(),b)-ids[k].begin();
			return bit[k].query(rig-1)-bit[k].query(lef-1);
		}
		ll vl=query(a,b,k*2+1,l,(l+r)/2);
		ll vr=query(a,b,k*2+2,(l+r)/2,r);
		return vl+vr;
	}
};

segtree seg;

int n,m;
int a[100001];
int tmp[100001];
set<int> now[100001];
int typ[100001],p[10001],val[100001];

int main(void){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
		a[i]--;
		now[a[i]].insert(i);
		tmp[i]=a[i];
	}
	for(int i=0;i<n;i++){
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.addnode(i,*it);
		}
	}
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&typ[i],&p[i],&val[i]);
		p[i]--;
		if(typ[i]==1){
			val[i]--;
			int prev=a[p[i]];
			if(prev==val[i])continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end() && it!=now[prev].begin()){
				it--;
				int f=*it;
				it++;
				seg.addnode(f,*it);
			}
			a[p[i]]=val[i];
			int next=a[p[i]];
			it=now[next].upper_bound(p[i]);
			if(it!=now[next].end()){
				seg.addnode(p[i],*it);
			}
			if(it!=now[next].begin()){
				it--;
				seg.addnode(*it,p[i]);
			}
			now[next].insert(p[i]);
		}
	}
	seg.init();
	for(int i=0;i<n;i++){
		now[i].clear();
		a[i]=tmp[i];
	}
	for(int i=n-1;i>=0;i--){
		now[a[i]].insert(i);
		set<int>::iterator it=now[a[i]].upper_bound(i);
		if(it!=now[a[i]].end()){
			seg.add(i,*it,(*it)-i);
		}
	}
	for(int i=0;i<m;i++){
		if(typ[i]==1){
			int prev=a[p[i]];
			if(val[i]==prev)continue;
			now[prev].erase(p[i]);
			set<int>::iterator it=now[prev].upper_bound(p[i]);
			if(it!=now[prev].end()){
				int va=*it;
				seg.add(p[i],va,p[i]-va);
				if(it!=now[prev].begin()){
					it--;
					seg.add(*it,p[i],(*it)-p[i]);
					seg.add(*it,va,va-(*it));
				}
			}else if(it!=now[prev].begin()){
				it--;
				seg.add(*it,p[i],(*it)-p[i]);
			}

			it=now[val[i]].upper_bound(p[i]);
			if(it!=now[val[i]].end()){
				seg.add(p[i],*it,(*it)-p[i]);
				if(it!=now[val[i]].begin()){
					int np=*it;
					it--;
					seg.add(*it,np,(*it)-np);
					seg.add(*it,p[i],p[i]-(*it));
				}
			}else if(it!=now[val[i]].begin()){
				it--;
				seg.add(*it,p[i],p[i]-(*it));
			}
			now[val[i]].insert(p[i]);
			a[p[i]]=val[i];
		}else{
			printf("%lld\n",seg.query(p[i],val[i]));
		}
	}
	return 0;
}


#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
#define int long long
const int N=100009;
#define val(x) (q[x].s*(q[x].b-q[x].a))
struct query
{
	int a,b,op,s;
} q[N*9],b[N*9];
int n,m,a[N],ans[N],cnt,cntq,tr[N];
set<int> Set[N];

inline void add(int x,int c){while(x<=n){tr[x]+=c,x+=(x&-x);}}
inline int ask(int x){int res=0;while(x){res+=tr[x],x-=(x&-x);}return res;}
inline bool cmp(query x,query y)
{
	if(x.op!=y.op) return x.op<y.op;
	else if(x.op) return x.a<y.a;
	else return x.b<y.b;
}
	// while(p1<=mid&&p2<=r)
	// {
	// 	if(q[p1].op==-1)
	// 	{
	// 		if(q[p1].a<=q[p2].a) add(q[p1].b,val(p1)),b[Cnt++]=q[p1++];
	// 	}
	// 	if(q[p2].op!=-1)
	// 	{
	// 		if(q[p1].a>q[p2].a) ans[q[p2].op]=ask(n)-ask(q[p2].b-1),b[Cnt++]=q[p2++];
	// 	}
	// }
	// while(p1<=mid)
	// 	if(q[p1].op==-1) add(q[p1].b,val(p1)),b[Cnt++]=q[p1++];
	// 	else p1++;
	// while(p2<=r)
	// 	if(q[p2].op!=-1) ans[q[p2].op]=ask(n)-ask(q[p2].b-1),b[Cnt++]=q[p2++];
	// 	else p2++;
	// puts("debuf");
void cdq(int l,int r)
{
	if(l>=r) return;
	int mid=(l+r)>>1;
	cdq(l,mid),cdq(mid+1,r);
	int p1=l,p2=mid+1,Cnt=l;
	// printf("%lld %lld\n",l,r);
	for(int i=mid+1;i<=r;i++)
		if(q[i].op)
		{
			while(p1<=mid&&(q[p1].b<=q[i].b))
			{
				if(!q[p1].op) add(q[p1].a,val(p1));
				p1++;
			}
			ans[q[i].op]+=ask(n)-ask(q[i].a-1);
		}

	for(int i=l;i<p1;i++) if(!q[i].op) add(q[i].a,-val(i));
	// sort(q+l,q+r+1,cmp);
	for(int k=l,i=l,j=mid+1;k<=r;k++) b[k]=(j>r||(i<=mid&&q[i].b<=q[j].b))?q[i++]:q[j++];
	for(int i=l;i<=r;i++) q[i]=b[i];
}

signed main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		Set[a[i]].insert(i);
		if(Set[a[i]].size()!=1)
			q[++cnt]={*(--Set[a[i]].rbegin()),i,0,1};
	}
	for(int i=1;i<=m;i++)
	{
		int op,b,c,l=0,r=0;
		scanf("%lld%lld%lld",&op,&b,&c);
		if(op==2)
		{
			q[++cnt]={b,c,++cntq,0};
		}
		else
		{
			set<int>::iterator i=Set[a[b]].find(b);
			if(i!=Set[a[b]].begin())
			{
				l=*--i;
				q[++cnt]={l,b,0,-1};//二维数点，找到前驱，撤销影响
				i++;
			}
			if(++i!=Set[a[b]].end())
			{
				r=*i;
				q[++cnt]={b,r,0,-1};
			}
			if(l&&r) q[++cnt]={l,r,0,1};//容斥，二维前缀和.
			Set[a[b]].erase(b);

			Set[c].insert(b);l=r=0;
			i=Set[c].find(b);a[b]=c;
			if(i!=Set[c].begin())
			{
				l=*--i;
				q[++cnt]={l,b,0,1};//二维数点，找到新前驱，更新
				i++;
			}
			if(++i!=Set[c].end())
			{
				r=*i;
				q[++cnt]={b,r,0,1};
			}
			if(l&&r) q[++cnt]={l,r,0,-1};
		}
	}//已经按时间排好了序
	// puts("Debug");
	// for(int i=1;i<=cnt;i++) printf("%lld %lld\n",q[i].a,q[i].b);
	cdq(1,cnt);
	// puts("Debug");
	for(int i=1;i<=cntq;i++) printf("%lld\n",ans[i]);
	return 0;
}


#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 1e6 + 10;

int n, m;
struct query{
	int op, x, y, val, id;
}q[N];
int ans[N];
set<int>s[N];
int pre[N], nxt[N];
int a[N];
int calpre(int x, int col)
{
	auto t = s[col].lower_bound(x);
	-- t;
	return *t;
}
int c[N];

int calnxt(int x, int col)
{
	auto t = s[col].upper_bound(x);
	return *t;
}

bool cmp(query a, query b)
{
	if(a.op != b.op) return a.op < b.op;
	if(a.op) return a.y < b.y;
	return a.x < b.x;
}

int lowbit(int x)
{
	return x & (-x);
}

void add(int x, int y)
{
	if(!x) return ;
	for (; x < N; x += lowbit(x))
		c[x] += y;
}

int ask(int x)
{
	int res = 0;
	for (; x; x -= lowbit(x))
		res += c[x];
	return res;
}

void cdq(int l, int r)
{
//	cout << l << " " << r << '\n';
	if(l >= r) return ;
	int mid = l + r >> 1;
	cdq(l, mid), cdq(mid + 1, r);
	int i = l, j = mid + 1;
	for (; j <= r; j ++)
	if(q[j].op == 1)
	{
		while(i <= mid && (q[i].op == 1 || q[i].x <= q[j].y))
		{
	//		cout << i << " " << j << '\n';
	//		cout << q[i].op << " " << q[i].id
			if(!q[i].op)
			{
	//			cout << q[i].y<< '\n';

				add(q[i].y, q[i].val);
			//	cout << q[i].val << '\n';
			}
			i ++;
		//out << i << '\n';
		}
//		if(q[j].op == 1)
		ans[q[j].id] += ask(n) - ask(q[j].x - 1);
	}

	for (int t = l; t <= i - 1; t ++)
		if(!q[t].op)
			add(q[t].y, -q[t].val);
	sort(q + l, q + r + 1, cmp);
//	cout << l << " " << r << '\n';
}
int tot, op, x, y;

signed main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i ++)
		s[i].insert(0), s[i].insert(n + 1);
	for (int i = 1; i <= n; i ++)
	{
		scanf("%d", &a[i]);
		s[a[i]].insert(i);
	}
	for (int i = 1; i <= n; i ++)
	{
		pre[i] = calpre(i, a[i]);
		nxt[i] = calnxt(i, a[i]);
	//	if(pre[i] != 0)
		q[++ tot] = {0, i, pre[i], i - pre[i], 0};
	}
	int c = 0;
	for (int i = 1; i <= m; i ++)
	{
		scanf("%d%d%d", &op, &x, &y);
		if(op == 1)
		{
			if(a[x] == y) continue;
			int Pre = calpre(x, y), Nxt = calnxt(x, y);
			s[a[x]].erase(x), s[y].insert(x);
			a[x] = y;
			if(nxt[x] != n + 1)
			{
				q[++ tot] = {0, nxt[x], pre[nxt[x]], pre[nxt[x]] - nxt[x], 0};
				pre[nxt[x]] = pre[x];
				q[++ tot] = {0, nxt[x], pre[nxt[x]], nxt[x] - pre[nxt[x]], 0};
			}
			if(pre[x] != 0) nxt[pre[x]] = nxt[x];
			if(Pre != 0) nxt[Pre] = x;
			if(Nxt != n + 1)
			{
				q[++ tot] = {0, Nxt, pre[Nxt], pre[Nxt] - Nxt, 0};
				pre[Nxt] = x;
				q[++ tot] = {0, Nxt, pre[Nxt], Nxt - pre[Nxt], 0};
			}
			q[++ tot] = {0, x, pre[x], pre[x] - x, 0};
			pre[x] = Pre;
			q[++ tot] = {0, x, pre[x], x - pre[x], 0};
		}
		else
		{
			++ c;
			q[++ tot] = {1, x, y, 0, c};
		}
	}
	cdq(1, tot);
//	for (int i = 1; i <= tot; i ++)
//	{
//		cout << q[i].op << " " << q[i].x << " " << q[i].y << " " << q[i].val << " " << q[i].id << '\n';
//	}
	for (int i = 1; i <= c; i ++)
		printf("%lld\n", ans[i]);
}


#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
map<int, long long> fen[N];
set<int> id[N];
int n, m, a[N];

void add(int p1, int p2, int x) {
	for (int l = p1; l < N; l += l & -l)
		for (int r = p2; r < N; r += r & -r)
			fen[l][r] += x;
}

long long get(int p1, int p2) {
	long long ans = 0;
	for (int l = p1; l; l -= l & -l)
		for (int r = p2; r; r -= r & -r)
			ans += fen[l].count(r)? fen[l][r]: 0;
	return ans;
}

void update(int p, int x) {
	auto it = id[a[p]].find(p);
	if (++it != id[a[p]].end())
		add(p, *it, x * (*it - p));
}

void change(int p, int x) {
	vector<int> vec = {p};
	auto it = id[a[p]].find(p);
	if (it != id[a[p]].begin())
		vec.push_back(*--it++);
	it = id[x].lower_bound(p);
	if (!id[x].empty() && it != id[x].begin())
		vec.push_back(*--it);
	for (auto pos: vec)
		update(pos, -1);
	id[a[p]].erase(p);
	id[a[p] = x].insert(p);
	for (auto pos: vec)
		update(pos, 1);
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", a + i);
		id[a[i]].insert(i);
	}
	for (int i = 1; i <= n; i++)
		update(i, 1);
	while (m--) {
		int t, x, y;
		scanf("%d%d%d", &t, &x, &y);
		if (t & 1)
			change(x, y);
		else
			--x, printf("%lld\n", get(x, x) - get(x, y) - get(y, x) + get(y, y));
	}
}


// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ri register int
#define For(i,j,k) for(ri i=j;i<=k;i=-~i)
inline int v_in(){
    int f=1,sum=0;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){sum=(sum<<3)+(sum<<1)+(ch^48);ch=getchar();}
    return sum*f;
}
const int M=1e5+5;
int n,m,tot,cnt,a[M];ll ans[M];
struct nd{
	int a,b,t,f;
	inline int val(){return (~f)?(a-b):(b-a);}
}A[M<<3],C[M<<3];
set<int>S[M];
struct bit{
	int c[M];
	inline int lowbit(int x){return x&(-x);}
	inline void add(int x,int w){while(x<=n)c[x]+=w,x+=lowbit(x);}
	inline int query(int x){int res=0;while(x)res+=c[x],x-=lowbit(x);return res;}
}T;
inline void merge(int l,int mid,int r){
	for(ri k=l,i=l,j=mid+1;k<=r;k++)C[k]=(j>r||(i<=mid&&A[i].a<=A[j].a))?A[i++]:A[j++];
	For(i,l,r)A[i]=C[i];
}
inline void cdq(int l,int r){
	int mid=(l+r)>>1,i,j;if(l>=r)return;
	cdq(l,mid);cdq(mid+1,r);
	for(i=mid+1,j=l;i<=r;i++)
		if(A[i].t){
			while(j<=mid&&A[j].a<=A[i].a){if(!A[j].t)T.add(A[j].b,A[j].val());j++;}
			ans[A[i].t]+=T.query(n)-T.query(A[i].b-1);
		}
	For(i,l,j-1)if(!A[i].t)T.add(A[i].b,-A[i].val());
	merge(l,mid,r);
}
int main(){
	n=v_in(),m=v_in();
	For(i,1,n){
		S[a[i]=v_in()].insert(i);
		if(S[a[i]].size()>1)A[++tot]=(nd){i,*(--S[a[i]].rbegin()),0,1};
	}
	For(i,1,m){
		int opo=v_in(),l=v_in(),r=v_in();
		if(opo==1){
			auto i=S[a[l]].find(l);int L=0,R=0;
			if(i!=S[a[l]].begin())A[++tot]=(nd){l,L=*--i,0,-1},i++;
			if(++i!=S[a[l]].end())A[++tot]=(nd){R=*i,l,0,-1};
			if(L&&R)A[++tot]=(nd){R,L,0,1};
			S[a[l]].erase(l);

			S[a[l]=r].insert(l),i=S[r].find(l),L=R=0;
			if(i!=S[r].begin())A[++tot]=(nd){l,L=*--i,0,1},i++;
			if(++i!=S[r].end())A[++tot]=(nd){R=*i,l,0,1};
			if(L&&R)A[++tot]=(nd){R,L,0,-1};
		}
		if(opo==2)A[++tot]=(nd){r,l,++cnt,0};
	}cdq(1,tot);
	For(i,1,cnt)printf("%lld\n",ans[i]);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

static mt19937 __gen(std::chrono::steady_clock::now().time_since_epoch().count());
static uniform_int_distribution<int> __distribution;
inline int randint(void) { return __distribution(__gen); }

constexpr int Maxn = 100005;
constexpr int inf = 0x3f3f3f3f;

namespace treap {
  constexpr int T_Maxn = ::Maxn * 20;
  struct node {
    static node *null;
    node *l, *r;
    int fix, size;
    int sum, val;
    int key, mn, mx;
    void *operator new (size_t size);
    void operator delete (void *ptr);
    node() { memset(this, 0, sizeof(*this)); }
    node(int key, int v)
    : key(key), val(v), sum(v) {
      mn = mx = key;
      l = r = null;
      fix = randint();
    }
    void pushup() {
      size = 1, sum = val;
      mn = mx = key;
      if (l) {
        size += l->size;
        sum += l->sum;
        mn = min(mn, l->mn);
        mx = max(mx, l->mx);
      }
      if (r) {
        size += r->size;
        sum += r->sum;
        mn = min(mn, r->mn);
        mx = max(mx, r->mx);
      }
    }
  } *node::null;
  #define null node::null
  static char pool[T_Maxn * sizeof(node)];
  char *tail(pool + sizeof(pool));
  void *recycle_stack[T_Maxn], **recycle_top(recycle_stack);
  inline void *node::operator new (size_t size) {
    return recycle_top != recycle_stack ? *--recycle_top : tail -= size;
  }
  inline void node::operator delete (void *ptr) {
    *recycle_top++ = ptr;
  }
  __attribute__((constructor))
  void clear() {
    tail = pool + sizeof(pool);
    null = new node; *null = node();
  }
  node *join(node *l, node *r) {
    if (l == null) return r;
    if (r == null) return l;
    if (l->fix < r->fix) {
      l->r = join(l->r, r);
      l->pushup();
      return l;
    }
    else {
      r->l = join(l, r->l);
      r->pushup();
      return r;
    }
  }
  pair<node*, node*> split(node* p,
      const function<bool(node*)> &is_left) {
    if (p == null)
      return {null, null};
    if (is_left(p)) {
      pair<node*, node*> tp = split(p->r, is_left);
      p->r = tp.first;
      p->pushup();
      return {p, tp.second};
    }
    else {
      pair<node*, node*> tp = split(p->l, is_left);
      p->l = tp.second;
      p->pushup();
      return {tp.first, p};
    }
  }
  pair<node*, node*> split_s(node* p, int k) {
    return split(p, [&](node *u) {
      int lsize = (u->l == nullptr ? 0 : u->l->size) + 1;
      if (k >= lsize) {
        k -= lsize;
        return true;
      }
      else {
        return false;
      }
    });
  }
  pair<node*, node*> split_k(node *p, int y, int v) {
    return split(p, [&](node *u) {
      return tie(u->key, u->val) < tie(y, v);
    });
  }
  void insert(node *&p, int y, int v) {
    pair<node*, node*> t1 = split_k(p, y, v - 1);
    p = join(join(t1.first, new node(y, v)), t1.second);
  }
  void remove(node *&p, int y, int v) {
    pair<node*, node*> t1 = split_k(p, y, v - 1);
    pair<node*, node*> t2 = split_s(t1.second, 1);
    p = join(t1.first, t2.second);
  }
  int query(node *&p, int y1, int y2) {
    pair<node*, node*> t1 = split_k(p, y1 - 1, inf);
    pair<node*, node*> t2 = split_k(t1.second, y2, inf);
    int res = t2.first->sum;
    p = join(join(t1.first, t2.first), t2.second);
    return res;
  }
}

namespace bit {
  vector<treap::node*> root;
  void init(size_t size) {
    root.resize(size + 2);
    fill(root.begin(), root.end(), treap::null);
  }
  void insert(int x, int y, int v) {
    while (x < (int)root.size()) {
      treap::insert(root[x], y, v);
      x += x & -x;
    }
  }
  void remove(int x, int y, int v) {
    while (x < (int)root.size()) {
      treap::remove(root[x], y, v);
      x += x & -x;
    }
  }
  int query(int x1, int y1, int x2, int y2) {
    if (x1 > x2) swap(x1, x2);
    if (y1 > y2) swap(y1, y2);
    int ans = 0; x1--;
    while (x2 > x1) {
      ans += treap::query(root[x2], y1, y2);
      x2 -= x2 & -x2;
    }
    while (x1 > x2) {
      ans -= treap::query(root[x1], y1, y2);
      x1 -= x1 & -x1;
    }
    return ans;
  }
}

int n, q;
int a[Maxn];
int pre[Maxn], last[Maxn];
set<int> st[Maxn];

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr), cout.tie(nullptr);
  cout << fixed << setprecision(12);

  cin >> n >> q;
  for (int i = 1; i <= n; ++i) {
    st[i].insert(0);
    st[i].insert(n + 1);
  }
  for (int i = 1; i <= n; ++i) {
    cin >> a[i];
    st[a[i]].insert(i);
    pre[i] = last[a[i]];
    last[a[i]] = i;
  }

  bit::init(n + 1);
  for (int i = 1; i <= n; ++i) {
    if (pre[i]) {
      bit::insert(i, pre[i], i - pre[i]);
    }
  }

  while (q--) {
    int op, x, y;
    cin >> op >> x >> y;
    if (op == 1) {
      {
        auto it = st[a[x]].find(x);
        int prv = *prev(it), nxt = *next(it);
        if (nxt <= n) {
          if (pre[nxt]) bit::remove(nxt, pre[nxt], nxt - pre[nxt]);
          pre[nxt] = prv;
          if (pre[nxt]) bit::insert(nxt, pre[nxt], nxt - pre[nxt]);
        }
        if (pre[x]) bit::remove(x, pre[x], x - pre[x]);
        st[a[x]].erase(it);
      }
      a[x] = y;
      {
        auto it = st[a[x]].insert(x).first;
        int prv = *prev(it), nxt = *next(it);
        if (prv <= n) {
          if (pre[nxt]) bit::remove(nxt, pre[nxt], nxt - pre[nxt]);
          pre[nxt] = x;
          bit::insert(nxt, pre[nxt], nxt - pre[nxt]);
        }
        pre[x] = prv;
        if (pre[x]) bit::insert(x, pre[x], x - pre[x]);
      }
    }
    else {
      cout << bit::query(1, x, y, n) << endl;
    }
  }

  return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define M 100005
using namespace std;
int n,m,val[M],T;
ll Ans[M];
struct node{
	int id,x,y,val;
	bool operator < (const node &_)const{
		if(x==_.x)return id<_.id;
		return x<_.x;
	}
}A[M<<3],B[M<<3];

set<int>st[M];
set<int>::iterator las,nxt,now;
void Insert(int x,int v){
	if(val[x]==v)return;
	//ɾ��
	if(val[x]!=v&&val[x]!=0){
		int p1=0,p2=0;
		now=las=nxt=st[val[x]].find(x);
		if(las!=st[val[x]].begin()){//ɾǰ
			las--;
			A[++T]=(node){0,x,*las,*las-x};
			p1=1;
		}
		nxt++;
		if(nxt!=st[val[x]].end()){//ɾ��
			A[++T]=(node){0,*nxt,x,x-*nxt};
			p2=1;
		}
		if(p1&&p2){//��ǰ��
			A[++T]=(node){0,*las,*nxt,*nxt-*las};
		}
		st[val[x]].erase(now);
	}
	//�ϲ�
	int p1=0,p2=0;
	st[v].insert(x);
	now=las=nxt=st[v].find(x);
	if(las!=st[v].begin()){//��ǰ
		las--;
		A[++T]=(node){0,*las,x,x-*las};
		p1=1;
	}
	nxt++;
	if(nxt!=st[v].end()){//����
		A[++T]=(node){0,x,*nxt,*nxt-x};
		p2=1;
	}
	if(p1&&p2){//��ǰ��
		A[++T]=(node){0,*nxt,*las,*las-*nxt};
	}
	val[x]=v;
}

void Insert2(int id,int x,int y){
	A[++T]=(node){id,y,y,1};
	A[++T]=(node){id,y,x-1,-1};
	A[++T]=(node){id,x-1,y,-1};
	A[++T]=(node){id,x-1,x-1,1};
}

struct BIT{
	ll sum[M<<3];
	void Add(int x,int y){
		while(x<=T){
			sum[x]+=y;
			x+=x&-x;
		}
	}
	ll Query(int x){
		ll res=0;
		while(x){
			res+=sum[x];
			x-=x&-x;
		}return res;
	}
	void Del(int x){
		while(x<=T){
			sum[x]=0;
			x+=x&-x;
		}
	}
}bit;

void solve(int L,int R){
	if(L==R)return;
	int mid=(L+R)>>1;
	solve(L,mid);solve(mid+1,R);
	int l=L,r=mid+1,k=l;
	while(l<=mid&&r<=R){
		if(A[l]<A[r]){
			if(!A[l].id)bit.Add(A[l].y,A[l].val);
			B[k++]=A[l++];
		}else{
			if(A[r].id)Ans[A[r].id]+=bit.Query(A[r].y)*A[r].val;
			B[k++]=A[r++];
		}
	}
	while(l<=mid)B[k++]=A[l++];
	while(r<=R){
		if(A[r].id)Ans[A[r].id]+=bit.Query(A[r].y)*A[r].val;
		B[k++]=A[r++];
	}
	for(int i=L;i<=mid;i++)if(!A[i].id)bit.Del(A[i].y);
	for(int i=L;i<=R;i++)A[i]=B[i];
}

int main(){
	int cnt=0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		int v;
		scanf("%d",&v);
		Insert(i,v);
	}
	for(int i=1;i<=m;i++){
		int op,x,y;
		scanf("%d%d%d",&op,&x,&y);
		if(op==1)Insert(x,y);
		else Insert2(++cnt,x,y);
	}
	solve(1,T);
	for(int i=1;i<=cnt;i++)
		printf("%lld\n",Ans[i]);
	return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define M 100005
using namespace std;
int n,m,val[M],L[M],R[M];
struct ASK{int op,l,r;}A[M];
int main(){
	while(scanf("%d%d",&n,&m)==2){
		for(int i=1;i<=n;i++)scanf("%d",&val[i]);
		for(int i=1;i<=m;i++){
			int op,l,r;
			scanf("%d%d%d",&op,&l,&r);
			A[i]=(ASK){op,l,r};
		}
		for(int i=1;i<=m;i++){
			if(A[i].op==1){
				val[A[i].l]=A[i].r;
			}else{
				ll sum=0;
				for(int j=A[i].l;j<=A[i].r;j++){
					L[val[j]]=1e9;R[val[j]]=0;
				}
				for(int j=A[i].l;j<=A[i].r;j++){
					int x=R[val[j]]-L[val[j]];
					L[val[j]]=min(L[val[j]],j);
					R[val[j]]=max(R[val[j]],j);
					if(x!=-1e9)sum=sum-x;
					sum+=R[val[j]]-L[val[j]];
				}
				printf("%lld\n",sum);
			}
		}
	}
	return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define M 100005
using namespace std;
int n,m,val[M],T;
ll Ans[M];
struct node{
	int id,x,y,val;
	bool operator < (const node &_)const{
		if(x==_.x)return id<_.id;
		return x<_.x;
	}
}A[M<<3],B[M<<3];

set<int>st[M];
set<int>::iterator las,nxt,now;
void Insert(int x,int v){
	if(val[x]==v)return;
	//ɾ��
	if(val[x]!=v&&val[x]!=0){
		int p1=0,p2=0;
		now=las=nxt=st[val[x]].find(x);
		if(las!=st[val[x]].begin()){//ɾǰ
			las--;
			A[++T]=(node){0,x,*las,*las-x};
			p1=1;
		}
		nxt++;
		if(nxt!=st[val[x]].end()){//ɾ��
			A[++T]=(node){0,*nxt,x,x-*nxt};
			p2=1;
		}
		if(p1&&p2){//��ǰ��
			A[++T]=(node){0,*las,*nxt,*nxt-*las};
		}
		st[val[x]].erase(now);
	}
	//�ϲ�
	int p1=0,p2=0;
	st[v].insert(x);
	now=las=nxt=st[v].find(x);
	if(las!=st[v].begin()){//��ǰ
		las--;
		A[++T]=(node){0,*las,x,x-*las};
		p1=1;
	}
	nxt++;
	if(nxt!=st[v].end()){//����
		A[++T]=(node){0,x,*nxt,*nxt-x};
		p2=1;
	}
	if(p1&&p2){//��ǰ��
		A[++T]=(node){0,*nxt,*las,*las-*nxt};
	}
	val[x]=v;
}

void Insert2(int id,int x,int y){
	A[++T]=(node){id,y,y,1};
	A[++T]=(node){id,y,x-1,-1};
	A[++T]=(node){id,x-1,y,-1};
	A[++T]=(node){id,x-1,x-1,1};
}

struct BIT{
	ll sum[M<<3];
	void Add(int x,int y){
		while(x<=T){
			sum[x]+=y;
			x+=x&-x;
		}
	}
	ll Query(int x){
		ll res=0;
		while(x){
			res+=sum[x];
			x-=x&-x;
		}return res;
	}
	void Del(int x){
		while(x<=T){
			sum[x]=0;
			x+=x&-x;
		}
	}
}bit;

void solve(int L,int R){
	if(L==R)return;
	int mid=(L+R)>>1;
	solve(L,mid);solve(mid+1,R);
	int l=L,r=mid+1,k=l;
	while(l<=mid&&r<=R){
		if(A[l]<A[r]){
			if(!A[l].id)bit.Add(A[l].y,A[l].val);
			B[k++]=A[l++];
		}else{
			if(A[r].id)Ans[A[r].id]+=bit.Query(A[r].y)*A[r].val;
			B[k++]=A[r++];
		}
	}
	while(l<=mid)B[k++]=A[l++];
	while(r<=R){
		if(A[r].id)Ans[A[r].id]+=bit.Query(A[r].y)*A[r].val;
		B[k++]=A[r++];
	}
	for(int i=L;i<=mid;i++){
		A[i]=B[i];
		if(!A[i].id)bit.Del(A[i].y);
	}
}

int main(){
	int cnt=0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		int v;
		scanf("%d",&v);
		Insert(i,v);
	}
	for(int i=1;i<=m;i++){
		int op,x,y;
		scanf("%d%d%d",&op,&x,&y);
		if(op==1)Insert(x,y);
		else Insert2(++cnt,x,y);
	}
	solve(1,T);
	for(int i=1;i<=cnt;i++)
		printf("%lld\n",Ans[i]);
	return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define M 100005
using namespace std;
int n,m,val[M],T;
ll Ans[M];
struct node{
	int id,x,y,val;
	bool operator < (const node &_)const{
		if(x==_.x)return id<_.id;
		return x<_.x;
	}
}A[M<<3],B[M<<3];

set<int>st[M];
set<int>::iterator las,nxt,now;
void Insert(int x,int v){
	if(val[x]==v)return;
	//ɾ��
	if(val[x]!=v&&val[x]!=0){
		int p1=0,p2=0;
		now=las=nxt=st[val[x]].find(x);
		if(las!=st[val[x]].begin()){//ɾǰ
			las--;
			A[++T]=(node){0,x,*las,*las-x};
			p1=1;
		}
		nxt++;
		if(nxt!=st[val[x]].end()){//ɾ��
			A[++T]=(node){0,*nxt,x,x-*nxt};
			p2=1;
		}
		if(p1&&p2){//��ǰ��
			A[++T]=(node){0,*las,*nxt,*nxt-*las};
		}
		st[val[x]].erase(now);
	}
	//�ϲ�
	int p1=0,p2=0;
	st[v].insert(x);
	now=las=nxt=st[v].find(x);
	if(las!=st[v].begin()){//��ǰ
		las--;
		A[++T]=(node){0,*las,x,x-*las};
		p1=1;
	}
	nxt++;
	if(nxt!=st[v].end()){//����
		A[++T]=(node){0,x,*nxt,*nxt-x};
		p2=1;
	}
	if(p1&&p2){//��ǰ��
		A[++T]=(node){0,*nxt,*las,*las-*nxt};
	}
	val[x]=v;
}

void Insert2(int id,int x,int y){
	A[++T]=(node){id,y,y,1};
	A[++T]=(node){id,y,x-1,-1};
	A[++T]=(node){id,x-1,y,-1};
	A[++T]=(node){id,x-1,x-1,1};
}

struct BIT{
	ll sum[M<<3];
	void Add(int x,int y){
		while(x<=T){
			sum[x]+=y;
			x+=x&-x;
		}
	}
	ll Query(int x){
		ll res=0;
		while(x){
			res+=sum[x];
			x-=x&-x;
		}return res;
	}
	void Del(int x){
		while(x<=T){
			sum[x]=0;
			x+=x&-x;
		}
	}
}bit;

void solve(int L,int R){
	if(L==R)return;
	int mid=(L+R)>>1;
	solve(L,mid);solve(mid+1,R);
	int l=L,r=mid+1,k=l;
	while(l<=mid&&r<=R){
		if(A[l]<A[r]){
			if(!A[l].id)bit.Add(A[l].y,A[l].val);
			B[k++]=A[l++];
		}else{
			if(A[r].id)Ans[A[r].id]+=bit.Query(A[r].y)*A[r].val;
			B[k++]=A[r++];
		}
	}
	while(l<=mid)B[k++]=A[l++];
	while(r<=R){
		if(A[r].id)Ans[A[r].id]+=bit.Query(A[r].y)*A[r].val;
		B[k++]=A[r++];
	}
	for(int i=L;i<=R;i++){
		A[i]=B[i];
		if(!A[i].id)bit.Del(A[i].y);
	}
}

int main(){
	int cnt=0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		int v;
		scanf("%d",&v);
		Insert(i,v);
	}
	for(int i=1;i<=m;i++){
		int op,x,y;
		scanf("%d%d%d",&op,&x,&y);
		if(op==1)Insert(x,y);
		else Insert2(++cnt,x,y);
	}
	solve(1,T);
	for(int i=1;i<=cnt;i++)
		printf("%lld\n",Ans[i]);
	return 0;
}


#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "cmath"
#include "vector"
#include "map"
#include "set"
#include "queue"
#include "assert.h"
using namespace std;
#define MAXN 1000006
//#define int long long
#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define all(x) (x).begin() , (x).end()
#define mem( a ) memset( a , 0 , sizeof a )
typedef long long ll;
int n , m;
int A[MAXN] , pre[MAXN] , lst[MAXN] , nxt[MAXN];

struct que {
	int op , x , y , c;
} Q[MAXN] , tmp[MAXN] ; int cnt; // 0 change

set<int> pos[MAXN];
inline int getpre( int x ) {
	return *( -- pos[A[x]].lower_bound( x ) );
}
inline int getnxt( int x ) {
	return *( pos[A[x]].upper_bound( x ) );
}

int ans[MAXN] , cn;

ll T[MAXN];
void add( int x , int c ) {
	assert( x );
	while( x <= n ) T[x] += c , x += ( x & -x );
}
int sum( int x ) {
	assert( x );
	int ret = 0;
	while( x > 0 ) ret += T[x] , x -= ( x & -x );
	return ret;
}

void cdq( int l , int r ) {
	if( l == r ) return;
	int m = l + r >> 1 , cc = 0;
	cdq( l , m ) , cdq( m + 1 , r );
	int L , R;
	for( L = l , R = m + 1 ; L <= m ; ++ L ) {
		while( R <= r && Q[R].x > Q[L].x ) {
			if( Q[R].op == 1 )
				ans[Q[R].c] += sum( Q[R].y );
			tmp[++ cc] = Q[R];
			++ R;
		}
		if( Q[L].op == 0 ) add( Q[L].y , Q[L].c );
		tmp[++ cc] = Q[L];
	}
	while( R <= r ) {
		if( Q[R].op == 1 )
			ans[Q[R].c] += sum( Q[R].y );
		tmp[++ cc] = Q[R];
		++ R;
	}
	rep( i , l , m ) if( Q[i].op == 0 ) add( Q[i].y , -Q[i].c );
	rep( i , l , r ) Q[i] = tmp[i - l + 1];
}

void solve() {
	cin >> n >> m;
	int pr;
	rep( i , 1 , n ) pos[i].insert( 0 ) , pos[i].insert( n + 1 );
	rep( i , 1 , n ) {
		scanf("%d",A + i);
		pos[A[i]].insert( i );
		pr = getpre( i );
		if( pr ) Q[++ cnt] = (que) { 0 , pr , i , i - pr };
	}
	int a , b , c , nx , nxx , prr;
	rep( i , 1 , m ) {
		scanf("%d%d%d",&a,&b,&c);
		if( a == 1 ) {
			pr = getpre( b ) , nx = getnxt( b );
			pos[A[b]].erase( b ) , A[b] = c , pos[A[b]].insert( b );
			prr = getpre( b ) , nxx = getnxt( b );
			if( nx != n + 1 ) Q[++ cnt] = (que) { 0 , b , nx , b - nx };
			if( pr ) Q[++ cnt] = (que) { 0 , pr , b , pr - b };
			if( pr && nx != n + 1 ) Q[++ cnt] = (que) { 0 , pr , nx , nx - pr };
			if( nxx != n + 1 ) Q[++ cnt] = (que) { 0 , b , nxx , nxx - b };
			if( prr ) Q[++ cnt] = (que) { 0 , prr , b , b - prr };
			if( prr && nxx != n + 1 ) Q[++ cnt] = (que) { 0 , prr , nxx , prr - nxx };
		} else {
			++ cn , Q[++ cnt] = (que) { 1 , b , c , cn };
		}
	}
//	rep( i , 1 , cnt ) printf("%d %d %d %d\n",Q[i].op,Q[i].x,Q[i].y,Q[i].c);
	cdq( 1 , cnt );
	rep( i , 1 , cn ) printf("%d\n",ans[i]);
}

signed main() {
//    int T;cin >> T;while( T-- ) solve();
    solve();
}