#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 = 1123456;
    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 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){
                    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 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(v->level){
                const link u = v->c[!v->c[0]->level];
                v->key = u->key;
                v->val = u->val;
                v = u;
            }

            v = v->par;
            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(){
            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>
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 RBST{
    unsigned yy=1145141919;
    inline unsigned xorshift(){yy=yy^(yy<<13);yy=yy^(yy>>17);return yy=yy^(yy<<5);}
    constexpr int MASK  = 65535;
    inline int randInt(){return (int) (xorshift()&MASK);}
    typedef int KEY;
    const int RBST_SIZE =2123456;

    struct node{
        KEY key,lb,ub;
        LL val,sum;
        int sz;
        node*lc;
        node*rc;
        node *p;//�e�ւ̃|�C���^
    };
    typedef pair<node*,node*> pn;
    inline int size(node* v){return !v?0:v->sz;}
    inline node* update(node*v){
        if(!v)return v;
        v->sz   = 1 + size(v->lc) + size(v->rc);
        v->ub   = !v->rc ? v->key : v->rc->ub;
        v->lb   = !v->lc ? v->key : v->lc->lb;
        v->sum  = v->val;
        v->sum += !v->lc?0:v->lc->sum;
        v->sum += !v->rc?0:v->rc->sum;
        v->p    = NULL;
        if(!!v->rc)v->rc->p=v;
        if(!!v->lc)v->lc->p=v;
        return v;
    }

    namespace pool{
        node mem[RBST_SIZE],*que[RBST_SIZE];
        int bg=0;
        struct RB{
            RB(){REP(i,RBST_SIZE) que[i] = &mem[i];}
        }ST;
        inline void push(node* m){
            que[--bg] = m;
        }
        inline node* get(node val){
            node* ret = que[bg++];
            *ret = val;
            return ret;
        }
        inline node *get(KEY v,LL val){
            return get(node{v,v,v,val,val,1,NULL,NULL,NULL});
        }

    }
    inline int lr(LL a,LL b){return randInt()*(a+b)<a*MASK;}
    //l ��r���}�[�W���Ă�
    node* merge(node *l,node *r){
        if(!l || !r)return !l ? r:l;
        node* ret;
        if( lr(l->sz,r->sz) ){
            l->rc = merge(l->rc,r);
            ret = update(l);
        }else{
            r->lc = merge(l,r->lc);
            ret = update(r);
        }
        return ret;
    }
    //(-inf,key),[key,inf) �ɕ���
    pn split(node *v,KEY key){
        if(!v) return pn(NULL,NULL);
        if(v->key < key){
            pn s = split(v->rc,key);
            v->rc = s.fi;
            return pn(update(v),s.se);
        }
        else {
            pn s = split(v->lc,key);
            v->lc = s.se;
            return pn(s.fi,update(v));
        }
    }
    node* lower_bound(node *v,KEY key){
        if(!v)return v;
        if(v->key < key){
            return lower_bound(v->rc,key);
        }
        else {
            node *u = lower_bound(v->lc,key);
            return !u ? v : u;
        }
    }
    node* min(node *v){
        return !v->lc?v:min(v->lc);
    }
    node* max(node *v){
        return !v->rc?v:max(v->rc);
    }

    node* nxt(node *v,node *p=NULL){
        if(!p){
            if(v->rc!=p)return min(v->rc);
        }
        else{
            if(!v->lc)return v;
        }
        return !v->p ? NULL :nxt(v->p,v);
    }
    node* prv(node *v,node *p=NULL){
        if(!p){
            if(v->lc!=p)return max(v->lc);
        }
        else{
            if(!v->rc)return v;
        }
        return !v->p ? NULL :prv(v->p,v);
    }

    struct RBST{
        node* root;
        RBST(){
            root = NULL;
        }
        bool isempty(){
            return !root;
        }
        int size(){
            if(isempty())return 0;
            else root->sz;
        }
        bool exist(KEY key){
            node *v=lower_bound(root,key);
            return !!v && v->key == key;
        }
        bool erase(KEY key){
            auto l_mr=split(root,key);

            auto m_r=split(l_mr.se,key+1);
            root = merge(l_mr.fi,m_r.se);

            if(!m_r.fi)return false;
            else {
                pool::push(m_r.fi);

                return true;
            }
        }
        bool insert(KEY key,LL val){
            node *ins=pool::get(key,val);
            auto l_r = split(root,key);
            root = merge(merge(l_r.fi,ins),l_r.se);
            return true;
        }
        LL get(KEY a,KEY b,node*v){
            if(v==NULL)return 0;
            if(a<=v->lb&&v->ub<=b){
                return v->sum;
            }
            if(v->ub<a||b<v->lb){
                return 0;
            }
            LL ret=a<=v->key&&v->key<=b?v->val:0;
            ret+=get(a,b,v->lc);
            ret+=get(a,b,v->rc);
            return ret;
        }
        LL get(KEY a,KEY b){
            return get(a,b,root);
        }
    };
}

typedef LL A;
typedef RBST::RBST B;
struct node{
    B b;
};
A mg(node& v,int key){
    return v.b.get(-1,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 = 4123456;
    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 = 6123456;
    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];
            }
            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>
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 RBST{
    unsigned yy=1145141919;
    inline unsigned xorshift(){yy=yy^(yy<<13);yy=yy^(yy>>17);return yy=yy^(yy<<5);}
    constexpr int MASK  = 65535;
    inline int randInt(){return (int) (xorshift()&MASK);}
    typedef int KEY;
    const int RBST_SIZE =2123456;

    struct node{
        KEY key,lb,ub;
        LL val,sum;
        int sz;
        node*lc;
        node*rc;
        node *p;//�e�ւ̃|�C���^
    };
    typedef pair<node*,node*> pn;
    inline int size(node* v){return !v?0:v->sz;}
    inline node* update(node*v){
        if(!v)return v;
        v->sz   = 1 + size(v->lc) + size(v->rc);
        v->ub   = !v->rc ? v->key : v->rc->ub;
        v->lb   = !v->lc ? v->key : v->lc->lb;
        v->sum  = v->val;
        v->sum += !v->lc?0:v->lc->sum;
        v->sum += !v->rc?0:v->rc->sum;
        v->p    = NULL;
        if(!!v->rc)v->rc->p=v;
        if(!!v->lc)v->lc->p=v;
        return v;
    }

    namespace pool{
        node mem[RBST_SIZE],*que[RBST_SIZE];
        int bg=0;
        struct RB{
            RB(){REP(i,RBST_SIZE) que[i] = &mem[i];}
        }ST;
        inline void push(node* m){
            que[--bg] = m;
        }
        inline node* get(node val){
            node* ret = que[bg++];
            *ret = val;
            return ret;
        }
        inline node *get(KEY v,LL val){
            return get(node{v,v,v,val,val,1,NULL,NULL,NULL});
        }

    }
    inline int lr(LL a,LL b){return randInt()*(a+b)<a*MASK;}
    //l ��r���}�[�W���Ă�
    node* merge(node *l,node *r){
        if(!l || !r)return !l ? r:l;
        node* ret;
        if( lr(l->sz,r->sz) ){
            l->rc = merge(l->rc,r);
            ret = update(l);
        }else{
            r->lc = merge(l,r->lc);
            ret = update(r);
        }
        return ret;
    }
    //(-inf,key),[key,inf) �ɕ���
    pn split(node *v,KEY key){
        if(!v) return pn(NULL,NULL);
        if(v->key < key){
            pn s = split(v->rc,key);
            v->rc = s.fi;
            return pn(update(v),s.se);
        }
        else {
            pn s = split(v->lc,key);
            v->lc = s.se;
            return pn(s.fi,update(v));
        }
    }
    node* lower_bound(node *v,KEY key){
        if(!v)return v;
        if(v->key < key){
            return lower_bound(v->rc,key);
        }
        else {
            node *u = lower_bound(v->lc,key);
            return !u ? v : u;
        }
    }
    node* min(node *v){
        return !v->lc?v:min(v->lc);
    }
    node* max(node *v){
        return !v->rc?v:max(v->rc);
    }

    node* nxt(node *v,node *p=NULL){
        if(!p){
            if(v->rc!=p)return min(v->rc);
        }
        else{
            if(!v->lc)return v;
        }
        return !v->p ? NULL :nxt(v->p,v);
    }
    node* prv(node *v,node *p=NULL){
        if(!p){
            if(v->lc!=p)return max(v->lc);
        }
        else{
            if(!v->rc)return v;
        }
        return !v->p ? NULL :prv(v->p,v);
    }

    struct RBST{
        node* root;
        RBST(){
            root = NULL;
        }
        bool isempty(){
            return !root;
        }
        int size(){
            if(isempty())return 0;
            else root->sz;
        }
        bool exist(KEY key){
            node *v=lower_bound(root,key);
            return !!v && v->key == key;
        }
        bool erase(KEY key){
            auto l_mr=split(root,key);

            auto m_r=split(l_mr.se,key+1);
            root = merge(l_mr.fi,m_r.se);

            if(!m_r.fi)return false;
            else {
                pool::push(m_r.fi);

                return true;
            }
        }
        bool insert(KEY key,LL val){
            node *ins=pool::get(key,val);
            auto l_r = split(root,key);
            root = merge(merge(l_r.fi,ins),l_r.se);
            return true;
        }
        LL get(KEY a,KEY b,node*v){
            if(v==NULL)return 0;
            if(a<=v->lb&&v->ub<=b){
                return v->sum;
            }
            if(v->ub<a||b<v->lb){
                return 0;
            }
            LL ret=a<=v->key&&v->key<=b?v->val:0;
            ret+=get(a,b,v->lc);
            ret+=get(a,b,v->rc);
            return ret;
        }
        LL get(KEY a,KEY b){
            return get(a,b,root);
        }
    };
}

typedef LL A;
typedef RBST::RBST B;
struct node{
    B b;
};
A mg(node& v,int key){
    return v.b.get(-1,key);
}
A mg(A l,A r){
    return l+r;
}
namespace ST{
    node mem[1][2123456];
    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 = 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 RBST{
    unsigned yy=1145141919;
    inline unsigned xorshift(){yy=yy^(yy<<13);yy=yy^(yy>>17);return yy=yy^(yy<<5);}
    constexpr int MASK  = 65535;
    inline int randInt(){return (int) (xorshift()&MASK);}
    typedef int KEY;
    const int RBST_SIZE =2123456;

    struct node{
        KEY key,lb,ub;
        LL val,sum;
        int sz;
        node*lc;
        node*rc;
        node *p;//�e�ւ̃|�C���^
    };
    typedef pair<node*,node*> pn;
    inline int size(node* v){return !v?0:v->sz;}
    inline node* update(node*v){
        if(!v)return v;
        v->sz   = 1 + size(v->lc) + size(v->rc);
        v->ub   = !v->rc ? v->key : v->rc->ub;
        v->lb   = !v->lc ? v->key : v->lc->lb;
        v->sum  = v->val;
        v->sum += !v->lc?0:v->lc->sum;
        v->sum += !v->rc?0:v->rc->sum;
        v->p    = NULL;
        if(!v->rc)v->rc->p=v;
        if(!v->lc)v->lc->p=v;
        return v;
    }

    namespace pool{
        node mem[RBST_SIZE],*que[RBST_SIZE];
        int bg=0;
        struct RB{
            RB(){REP(i,RBST_SIZE) que[i] = &mem[i];}
        }ST;
        void push(node* m){
            que[--bg] = m;
        }
        node* get(node val){
            node* ret = que[bg++];
            *ret = val;
            return ret;
        }
        node *get(KEY v,LL val){
            return get(node{v,v,v,val,val,1,NULL,NULL,NULL});
        }

    }
    inline int lr(LL a,LL b){return randInt()*(a+b)<a*MASK;}
    //l ��r���}�[�W���Ă�
    node* merge(node *l,node *r){
        if(!l || !r)return !l ? update(r):update(l);
        node* ret;
        if( lr(l->sz,r->sz) ){
            l->rc = merge(l->rc,r);
            ret= update(l);
        }else{
            r->lc = merge(l,r->lc);
            ret= update(r);
        }
        return ret;
    }
    //(-inf,key),[key,inf) �ɕ���
    pn split(node *v,KEY key){
        if(!v) return pn(NULL,NULL);
        if(v->key < key){
            pn s = split(v->rc,key);
            v->rc = s.fi;
            return pn(update(v),s.se);
        }
        else {
            pn s = split(v->lc,key);
            v->lc = s.se;
            return pn(s.fi,update(v));
        }
    }
    node* lower_bound(node *v,KEY key){
        if(!v)return v;
        if(v->key < key){
            return lower_bound(v->rc,key);
        }
        else {
            node *u = lower_bound(v->lc,key);
            return !u ? v : u;
        }
    }
    node* min(node *v){
        return !v->lc?v:min(v->lc);
    }
    node* max(node *v){
        return !v->rc?v:max(v->rc);
    }

    node* nxt(node *v,node *p=NULL){
        if(!p){
            if(v->rc!=p)return min(v->rc);
        }
        else{
            if(!v->lc)return v;
        }
        return !v->p ? NULL :nxt(v->p,v);
    }
    node* prv(node *v,node *p=NULL){
        if(!p){
            if(v->lc!=p)return max(v->lc);
        }
        else{
            if(!v->rc)return v;
        }
        return !v->p ? NULL :prv(v->p,v);
    }

    struct RBST{
        node* root;
        RBST(){
            root = NULL;
        }
        bool isempty(){
            return !root;
        }
        int size(){
            if(isempty())return 0;
            else root->sz;
        }
        bool exist(KEY key){
            node *v=lower_bound(root,key);
            return !!v && v->key == key;
        }
        bool erase(KEY key){
            auto l_mr=split(root,key);

            auto m_r=split(l_mr.se,key+1);
            root = merge(l_mr.fi,m_r.se);

            if(!m_r.fi)return false;
            else {
                pool::push(m_r.fi);

                return true;
            }
        }
        bool insert(KEY key,LL val){
            node *ins=pool::get(key,val);
            auto l_r = split(root,key);
            root = merge(merge(l_r.fi,ins),l_r.se);
            return true;
        }
        LL get(KEY a,KEY b,node*v){
            if(v==NULL)return 0;
            if(a<=v->lb&&v->ub<=b){
                return v->sum;
            }
            if(v->ub<a||b<v->lb){
                return 0;
            }
            LL ret=a<=v->key&&v->key<=b?v->val:0;
            ret+=get(a,b,v->lc);
            ret+=get(a,b,v->rc);
            return ret;
        }
        LL get(KEY a,KEY b){
            return get(a,b,root);
        }
    };
}

typedef LL A;
typedef RBST::RBST B;
struct node{
    B b;
};
A mg(node& v,int key){
    return v.b.get(-1,key);
}
A mg(A l,A r){
    return l+r;
}
namespace ST{
    node mem[1][2123456];
    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){
        node q;
        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;
        }
    }

    auto check=[&](){
        FOR(l,1,n+1)FOR(r,l,n+1){
            vector<set<int>> s(n);
            FOR(i,l-1,r)s[v[i]].insert(i);
            LL ans=0;

            REP(i,n)if(s[i].size()){
                ans+=(*s[i].rbegin())-(*s[i].begin());
            }

            if(ans!=seg.get(l-1,r)){
                return false;
            }
        }
        return true;
    };

    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;
}