//dp001
/*#include<iostream>
using namespace std;

int main(){
    long long n,i;// number of inputs
    cin>>n;

    long long*ar= new long long[n];
    for(i=0;i<n;i++){
        cin>>ar[i];
    }
    long long*savec=new long long[n];
    long long c=1;
    long long k=0;
        if(n==1){
            cout<<ar[0];
        }
        else{
        for(long long j=1;j<n;j++){
            if(ar[j-1]<=ar[j]){
                ++c;
                savec[k]=c;
                k++;
            }
            else{
                c=1;
            }
        }
        long long max=savec[0];
        for(i=1;i<k;i++){
            if(savec[i]>=max)
                max=savec[i];
        }

        cout<<max;
        }
        return 0;
}
Almost worked:(
*/

#include <iostream>
using namespace std;

int main()
{
    int n, l(1), ml(1);
    cin >> n;
    int profits[n];

    for (int i = 0; i < n; i++)
    {
        cin >> profits[i];
        if (i > 0)
            if (profits[i] >= profits[i - 1])
            {
                l++;
                ml = max(ml, l);
            }
            else
                l = 1;
    }

    cout << ml << endl;
    return 0;
}


//dp001
#include<iostream>
using namespace std;

int main(){
    int n,i;// number of inputs
    cin>>n;

    long*ar= new long[n];
    for(i=0;i<n;i++){
        cin>>ar[i];
    }
    int*savec=new int[n];
    int c=1;
    int k=0;
        if(n==1){
            cout<<ar[0];
        }
        else{
        for(int j=1;j<n;j++){
            if(ar[j-1]<=ar[j]){
                ++c;
                savec[k]=c;
                k++;
            }
            else{
                c=1;
            }
        }
        int max=savec[0];
        for(i=1;i<k;i++){
            if(savec[i]>=max)
                max=savec[i];
        }

        cout<<max;
        }
        return 0;
}


//dp001
#include<iostream>
using namespace std;

int main(){
    int n,i;// number of inputs
    cin>>n;

    int*ar= new int[n];
    for(i=0;i<n;i++){
        cin>>ar[i];
    }
    int savec;
    int c=1;
        for(int j=1;j<n;j++){
            if(ar[j-1]<=ar[j]){
                c++;
                savec=c;
            }
            else{
                c=1;
            }
        }

        cout<<savec;
        return 0;
}


#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define pt(ch) (Top<1000000?St[Top++]=ch:(Out(),St[(Top=0)++]=ch))
#define Out() (fwrite(St,1,Top,stdout))
#define LL unsigned int
using namespace std;
int Top;
static char St[1000000],buf[1000000],*p1=buf,*p2=buf;
const int maxn=(1e5)+5;
int N,M,T,Q,P[maxn],cnt;
LL Ans[maxn],c[maxn];
set<int>S[maxn];
struct ff {
	int x,y,o,f;
	inline int val() {
		return (~f)?(x-y):(y-x);
	}
} A[maxn<<3],C[maxn<<3];
int Re() {
	int ret=0;
	char ch=gt();
	while(ch<'0'||ch>'9') ch=gt();
	while(ch>='0'&&ch<='9') ret=ret*10+(ch^'0'),ch=gt();
	return ret;
}
void Wri(LL x) {
	if(x>9) Wri(x/10);
	pt(x%10+'0');
}
void Add(int i,int x) {
	while(i<=N) c[i]+=x,i+=i&-i;
}
int Get(int i) {
	int Res=0;
	while(i) Res+=c[i],i^=i&-i;
	return Res;
}
void Merge(int L,int mid,int R) {
	for(int k=L,i=L,j=mid+1; k<=R; k++) C[k]=(j>R||(i<=mid&&A[i].x<=A[j].x))?A[i++]:A[j++];
	for(int k=L; k<=R; k++) A[k]=C[k];
}
void Solve(int L,int R) {
	if(L>=R) return;
	int mid=L+R>>1,i,j;
	Solve(L,mid),Solve(mid+1,R);
	for(i=mid+1,j=L; i<=R; i++)if(A[i].o) {
			while(j<=mid&&A[j].x<=A[i].x) {
				if(!A[j].o) Add(A[j].y,A[j].val());
				j++;
			}
			Ans[A[i].o]+=Get(N)-Get(A[i].y-1);
		}
	for(i=L; i<j; i++) if(!A[i].o) Add(A[i].y,-A[i].val());
	Merge(L,mid,R);
}
int main() {
	N=Re(),Q=Re();
	for(int i=1; i<=N; i++) {
		S[P[i]=Re()].insert(i);
		if(S[P[i]].size()>1)
			A[++M]=(ff) {
			i,*(--S[P[i]].rbegin()),0,1
		};
	}
	while(Q--) {
		int opt=Re(),x=Re(),y=Re();
		++T;
		if(opt==2) {
			A[++M]=(ff) {
				y,x,++cnt,0
			};
			continue;
		}
		auto i=S[P[x]].find(x);
		int L=0,R=0;
		if(i!=S[P[x]].begin()) A[++M]=(ff) {x,L=*--i,0,-1},i++;
		if(++i!=S[P[x]].end()) A[++M]=(ff) {
			R=*i,x,0,-1
		};
		if(L&&R) A[++M]=(ff) {
			R,L,0,1
		};
		S[P[x]].erase(x);

		S[P[x]=y].insert(x),i=S[y].find(x),L=R=0;
		if(i!=S[y].begin()) A[++M]=(ff) {x,L=*--i,0,1},i++;
		if(++i!=S[y].end()) A[++M]=(ff) {
			R=*i,x,0,1
		};
		if(L&&R) A[++M]=(ff) {
			R,L,0,-1
		};
	}
	Solve(1,M);
	for(int i=1; i<=cnt; i++) Wri(Ans[i]),pt('\n');
	return Out(),0;
}


#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
set<int> s[N];
int v[N],n,totq,sum[N],ans[N];
struct oper{
	int a,b,id,ot;
	bool ty;
	oper(int a=0,int b=0,bool ty=0,int ot=0) {this->a=a,this->b=b,this->ty=ty;this->ot=ot;}

}o[N];
inline int pre(int x){
	if(s[v[x]].find(x)==s[v[x]].begin()) return 0;
	return *--s[v[x]].find(x);
}
inline int nxt(int x){//cout<<x<<' '<<"QwQ"<<v[x]<<endl;
	auto it=s[v[x]].find(x);//cout<<' '<<"qwq"<<(*++it)<<endl;
	if(it==--s[v[x]].end()) return x;
	return *++it;
}
inline bool cmp1(oper a,oper b){
	return a.a+a.b<b.a+b.b;
}
inline bool cmp2(oper a,oper b){
	return a.b<b.b;
}
inline void ins(int x,int y) {for(int i=x;i<=n;i+=i&-i) sum[i]+=y;}
inline int que(int x) {int ans=0;for(int i=x;i;i-=i&-i) ans+=sum[i];return ans;}
void CDQ(int l,int r){

	if(l==r) return ;
	int m=l+r>>1,tl=l;
	CDQ(l,m),CDQ(m+1,r);
	sort(o+l,o+m+1,cmp1),sort(o+m+1,o+r+1,cmp2);
	for(int i=m+1;i<=r;++i){
		while(tl<=m&&o[tl].a+o[tl].b<=o[i].b) {
			if(o[tl].ty)ins(o[tl].a,o[tl].ot*o[tl].b);++tl;
		}
		if(!o[i].ty)ans[o[i].id]+=que(o[i].b)-que(o[i].a-1);
	}
	for(int i=l;i<tl;++i){
		if(o[i].ty)ins(o[i].a,-o[i].ot*o[i].b);
	}
	return ;
}
int main(){
	int m;cin>>n>>m;int totp=0;
	for(int i=1;i<=n;++i) scanf("%d",&v[i]),s[v[i]].insert(i);int totq=0;
	for(int i=1;i<=n;++i) o[++totq]=oper(i,nxt(i)-i,1,1);
	for(int i=1;i<=m;++i){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		--a;//cout<<a<<' '<<b<<' '<<c<<endl;
		if(a) o[++totq]=oper(b,c,0),o[totq].id=++totp;
		else {
			int d=pre(b),e=nxt(b);
			o[++totq]=oper(b,e-b,1,-1);
			if(d) o[++totq]=oper(d,b-d,1,-1),o[++totq]=oper(d,e==b?0:e-d,1,1);
			s[v[b]].erase(b);s[v[b]=c].insert(b);//cout<<v[b]<<' '<<e<<endl;
			d=pre(b);e=nxt(b);o[++totq]=oper(b,e-b,1,1);
			if(d) o[++totq]=oper(d,e==b?0:e-d,1,-1),o[++totq]=oper(d,b-d,1,1);
		}
	}
	CDQ(1,totq);
	for(int i=1;i<=totp;++i) printf("%d\n",ans[i]);
	return 0;
}


#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
using pii = pair<int, int>;

const int N = 1e5+10;
const int M = 1000;

int nxt[N], rt[N];

long long B[N/M+5][N];

inline void update(int id, int u, int d) {
	for(; u<N; u+=u&-u) B[id][u] += d;
}

inline long long calc(int id, int u) {
	long long ans = 0;
	for(; u>0; u-=u&-u) ans += B[id][u];
	return ans;
}

long long get(int L, int R) {
	long long ans = 0;
	for(int i=L; i<=R && rt[i] == rt[L]; i++) {
		if(nxt[i] <= R) {
			ans += nxt[i]-i;
		}
	}
	if(rt[L] != rt[R]) {
		for(int i=R; i>=L && rt[i] == rt[R]; i--) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
	}
	for(int id = rt[L] + 1; id < rt[R]; id++) {
		ans += calc(id, R);
	}
	return ans;
}

void add_seg(int L, int R) {
	update(rt[L], R, R-L);
}

void sub_seg(int L, int R) {
	update(rt[L], R, L-R);
}

int a[N], n;

set<pii> rev;
set<pii> :: iterator it1, it2;

void Erase(pii p) {
	pii q = p;
	swap(q.x, q.y);
	int L, R;
	it1 = rev.lower_bound(q);
	if(it1 == rev.begin() || (--it1)->x != q.x) L = 0;
	else L = it1->y;
	it2 = rev.upper_bound(q);
	if(it2 == rev.end() || it2->x != q.x) R = n+1;
	else R = it2->y;
	if(L>0 && R<n+1) add_seg(L, R);
	if(L>0) sub_seg(L, p.x);
	if(R<n+1) sub_seg(p.x, R);
	nxt[L] = R;
	rev.erase(q);
}

void Insert(pii p) {
	pii q = p;
	swap(q.x, q.y);
	int L, R;
	it1 = rev.lower_bound(q);
	if(it1 == rev.begin() || (--it1)->x != q.x || it1->y >= q.y) L = 0;
	else L = it1->y;
	it2 = rev.upper_bound(q);
	if(it2 == rev.end() || it2->x != q.x) R = n+1;
	else R = it2->y;
	if(L>0 && R<n+1) sub_seg(L, R);
	if(L>0) add_seg(L, p.x);
	if(R<n+1) add_seg(p.x, R);
	nxt[L] = p.x;
	nxt[p.x] = R;
	rev.insert(q);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("C.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	int m;
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; i++) {
		nxt[i] = n+1;
		rt[i] = (i-1)/M;
	}
	for(int i=1; i<=n; i++) {
		scanf("%d", a+i);
		Insert(pii(i, a[i]));
	}
	for(int typ, x, y; m--;) {
		scanf("%d %d %d", &typ, &x, &y);
		if(typ == 1) {
			Erase(pii(x, a[x]));
			a[x] = y;
			Insert(pii(x, a[x]));
		}else {
			printf("%I64d\n", get(x, y));
		}
	}
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

using INT = long long;

const int NN = 101000;
const int D = 222;

int n, m;
pair<int, int> cnt[1010][D+10];
int sz[1010];
//vector<pair<int, int> > cnt[NN];
int nxt[NN], root[NN], a[NN];
set<int> st[NN];

int build(int u) {
	if(u == 0) return 0;
	int L = (u - 1) * D + 1, R = min(n, u * D);
	sz[u] = 0;
	for(int i=L; i<=R; i++) {
		cnt[u][sz[u]++] = {nxt[i], nxt[i] - i};
	}
	sort(cnt[u], cnt[u]+sz[u]);
	for(int i=1; i<sz[u]; i++) cnt[u][i].second += cnt[u][i-1].second;
}

INT calc(int L, int R) {
	INT ans = 0;
	for(int i=L; i<=R and root[i] == root[L]; i++) {
		ans += (INT) (nxt[i] - i) * (nxt[i] <= R);
	}
	for(int i=R; root[i] == root[R] and root[i] != root[L]; i--) {
		ans += (INT) (nxt[i] - i) * (nxt[i] <= R);
	}
	for(int i=root[L]+1; i<root[R]; i++) {
		int x = upper_bound(cnt[i], cnt[i]+sz[i], make_pair(R+1, -1)) - cnt[i];
		if(x == 0) continue; x--;
		ans += cnt[i][x].second;
	}
	return ans;
}

int calc_nxt(int u) {
	if(u == 0) return 0;
	auto it = st[a[u]].upper_bound(u);
	if(it == st[a[u]].end()) return nxt[u] = u;
	return nxt[u] = *it;
}

int calc_pre(int u) {
	if(u == 0) return 0;
	auto it = st[a[u]].lower_bound(u);
	if(it == st[a[u]].begin()) return 0;
	return nxt[*--it] = u, *it;
}

int update(int u, int p) {
	int p1 = calc_pre(u);
	st[a[u]].erase(u); a[u] = p; st[a[u]].insert(u);
	calc_nxt(u); calc_nxt(p1);
	int p2 = calc_pre(u); build(root[p1]);
	if(root[p1] != root[u]) build(root[u]);
	if(root[p2] != root[p1] and root[p2] != root[u]) build(root[p2]);
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
#endif
	cin >> n >> m;
	for(int i=1; i<=n; i++) {
		scanf("%d", a+i);
		root[i] = (D + i - 1) / D;
		st[a[i]].insert(i);
	}
	for(int i=1; i<=n; i++) {
		calc_nxt(i);
	}
	for(int i=1; i<=n; i+=D) {
		build(root[i]);
	}
	for(int i=1; i<=m; i++) {
		int op, L, R;
		scanf("%d %d %d", &op, &L, &R);
		if(op == 1) update(L, R);
		else printf("%I64d\n", calc(L, R));
	}
	return 0;
}


#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
using pii = pair<int, int>;

const int N = 1e5+10;
const int M = 800;

int nxt[N], rt[N];

long long B[N/M+5][N];

void update(int id, int u, int d) {
	for(; u<N; u+=u&-u) B[id][u] += d;
}

long long calc(int id, int u) {
	long long ans = 0;
	for(; u>0; u-=u&-u) ans += B[id][u];
	return ans;
}

long long get(int L, int R) {
	long long ans = 0;
	if(rt[R] <= rt[L] + 1) {
		for(int i=L; i<=R; i++) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
	}else {
		for(int i=L; i<=R && rt[i] == rt[L]; i++) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
		for(int i=R; i>=L && rt[i] == rt[R]; i--) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
		for(int id = rt[L] + 1; id < rt[R]; id++) {
			ans += calc(id, R);
		}
	}
	return ans;
}

void add_seg(int L, int R) {
	update(rt[L], R, R-L);
}

void sub_seg(int L, int R) {
	update(rt[L], R, L-R);
}

int a[N], n;

set<pii> rev;
set<pii> :: iterator it1, it2;

void Erase(pii p) {
	pii q = p;
	swap(q.x, q.y);
	int L, R;
	it1 = rev.lower_bound(q);
	if(rev.empty() || it1 == rev.begin()) {
		L = 0;
	}else {
		it1--;
		if(it1->x != q.x) {
			L = 0;
		}else {
			L = it1->y;
		}
	}

	it2 = rev.upper_bound(q);
	if(it2 == rev.end()) {
		R = n+1;
	}else {
		if(it2->x != q.x) {
			R = n+1;
		}else {
			R = it2->y;
		}
	}

	if(L>0 && R<n+1) {
		add_seg(L, R);
	}
	if(L>0) {
		sub_seg(L, p.x);
	}
	if(R<n+1) {
		sub_seg(p.x, R);
	}

	nxt[L] = R;

	rev.erase(q);
}

void Insert(pii p) {
	pii q = p;
	swap(q.x, q.y);
	int L, R;
	it1 = rev.lower_bound(q);
	if(rev.empty() || it1 == rev.begin()) {
		L = 0;
	}else {
		it1--;
		if(it1->x != q.x || it1->y >= q.y) {
			L = 0;
		}else {
			L = it1->y;
		}
	}
	it2 = rev.upper_bound(q);
	if(it2 == rev.end()) {
		R = n+1;
	}else {
		if(it2->x != q.x) {
			R = n+1;
		}else {
			R = it2->y;
		}
	}
	if(L>0 && R<n+1) {
		sub_seg(L, R);
	}
	if(L>0) {
		nxt[L] = p.x;
		add_seg(L, p.x);
	}
	nxt[p.x] = R;
	if(R<n+1) {
		add_seg(p.x, R);
	}
	rev.insert(q);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("C.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	int m;
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; i++) {
		nxt[i] = n+1;
		rt[i] = (i-1)/M;
	}
	for(int i=1; i<=n; i++) {
		scanf("%d", a+i);
		Insert(pii(i, a[i]));
	}
	for(int typ, x, y; m--;) {
		scanf("%d %d %d", &typ, &x, &y);
		if(typ == 1) {
			Erase(pii(x, a[x]));
			a[x] = y;
			Insert(pii(x, a[x]));
		}else {
			printf("%I64d\n", get(x, y));
		}
	}
	return 0;
}


#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
using pii = pair<int, int>;

const int N = 1e5+10;
const int M = sqrt(N)+5;

int nxt[N], rt[N];

long long B[M][N];

void update(int id, int u, int d) {
	for(; u<N; u+=u&-u) B[id][u] += d;
}

long long calc(int id, int u) {
	long long ans = 0;
	for(; u>0; u-=u&-u) ans += B[id][u];
	return ans;
}

long long get(int L, int R) {
	long long ans = 0;
	if(rt[R] <= rt[L] + 1) {
		for(int i=L; i<=R; i++) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
	}else {
		for(int i=L; i<=R && rt[i] == rt[L]; i++) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
		for(int i=R; i>=L && rt[i] == rt[R]; i--) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
		for(int id = rt[L] + 1; id < rt[R]; id++) {
			ans += calc(id, R);
		}
	}
	return ans;
}

void add_seg(int L, int R) {
	update(rt[L], R, R-L);
}

void sub_seg(int L, int R) {
	update(rt[L], R, L-R);
}

int a[N], n;

set<pii> rev;
set<pii> :: iterator it1, it2;

void Erase(pii p) {
	pii q = p;
	swap(q.x, q.y);
	int L, R;
	it1 = rev.lower_bound(q);
	if(rev.empty() || it1 == rev.begin()) {
		L = 0;
	}else {
		it1--;
		if(it1->x != q.x) {
			L = 0;
		}else {
			L = it1->y;
		}
	}

	it2 = rev.upper_bound(q);
	if(it2 == rev.end()) {
		R = n+1;
	}else {
		if(it2->x != q.x) {
			R = n+1;
		}else {
			R = it2->y;
		}
	}

	if(L>0 && R<n+1) {
		add_seg(L, R);
	}
	if(L>0) {
		sub_seg(L, p.x);
	}
	if(R<n+1) {
		sub_seg(p.x, R);
	}

	nxt[L] = R;

	rev.erase(q);
}

void Insert(pii p) {
	pii q = p;
	swap(q.x, q.y);
	int L, R;
	it1 = rev.lower_bound(q);
	if(rev.empty() || it1 == rev.begin()) {
		L = 0;
	}else {
		it1--;
		if(it1->x != q.x || it1->y >= q.y) {
			L = 0;
		}else {
			L = it1->y;
		}
	}
	it2 = rev.upper_bound(q);
	if(it2 == rev.end()) {
		R = n+1;
	}else {
		if(it2->x != q.x) {
			R = n+1;
		}else {
			R = it2->y;
		}
	}
	if(L>0 && R<n+1) {
		sub_seg(L, R);
	}
	if(L>0) {
		nxt[L] = p.x;
		add_seg(L, p.x);
	}
	nxt[p.x] = R;
	if(R<n+1) {
		add_seg(p.x, R);
	}
	rev.insert(q);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("C.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	int m;
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; i++) {
		nxt[i] = n+1;
		rt[i] = (i-1)/M+1;
	}
	for(int i=1; i<=n; i++) {
		scanf("%d", a+i);
		Insert(pii(i, a[i]));
	}
	for(int typ, x, y; m--;) {
		scanf("%d %d %d", &typ, &x, &y);
		if(typ == 1) {
			Erase(pii(x, a[x]));
			a[x] = y;
			Insert(pii(x, a[x]));
		}else {
			printf("%I64d\n", get(x, y));
		}
	}
	return 0;
}


#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
using pii = pair<int, int>;

const int N = 1e5+10;
const int M = sqrt(N)+5;

int nxt[N], rt[N];

long long B[M][N];

void update(int id, int u, int d) {
	for(; u<N; u+=u&-u) B[id][u] += d;
}

long long calc(int id, int u) {
	long long ans = 0;
	for(; u>0; u-=u&-u) ans += B[id][u];
	return ans;
}

long long get(int L, int R) {
	long long ans = 0;
	if(rt[R] <= rt[L] + 1) {
		for(int i=L; i<=R; i++) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
	}else {
		for(int i=L; i<=R && rt[i] == rt[L]; i++) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
		for(int i=R; i>=L && rt[i] == rt[R]; i--) {
			if(nxt[i] <= R) {
				ans += nxt[i]-i;
			}
		}
		for(int id = rt[L] + 1; id < rt[R]; id++) {
			ans += calc(id, R);
		}
	}
	return ans;
}

void add_seg(int L, int R) {
	update(rt[L], R, R-L);
}

void sub_seg(int L, int R) {
	update(rt[L], R, L-R);
}

int a[N], n;

set<pii> rev;
set<pii> :: iterator it1, it2;

void Erase(pii p) {
	pii q = p;
	swap(q.x, q.y);
	int L, R;
	it1 = rev.lower_bound(q);
	if(rev.empty() || it1 == rev.begin()) {
		L = 0;
	}else {
		it1--;
		if(it1->x != q.x) {
			L = 0;
		}else {
			L = it1->y;
		}
	}

	it2 = rev.upper_bound(q);
	if(it2 == rev.end()) {
		R = n+1;
	}else {
		if(it2->x != q.x) {
			R = n+1;
		}else {
			R = it2->y;
		}
	}

	if(L>0 && R<n+1) {
		add_seg(L, R);
	}
	if(L>0) {
		sub_seg(L, p.x);
	}
	if(R<n+1) {
		sub_seg(p.x, R);
	}

	nxt[L] = R;

	rev.erase(q);
}

void Insert(pii p) {
	pii q = p;
	swap(q.x, q.y);
	int L, R;
	it1 = rev.lower_bound(q);
	if(rev.empty() || it1 == rev.begin()) {
		L = 0;
	}else {
		it1--;
		if(it1->x != q.x || it1->y >= q.y) {
			L = 0;
		}else {
			L = it1->y;
		}
	}
	it2 = rev.upper_bound(q);
	if(it2 == rev.end()) {
		R = n+1;
	}else {
		if(it2->x != q.x) {
			R = n+1;
		}else {
			R = it2->y;
		}
	}
	if(L>0 && R<n+1) {
		sub_seg(L, R);
	}
	if(L>0) {
		nxt[L] = p.x;
		add_seg(L, p.x);
	}
	if(R<n+1) {
		nxt[p.x] = R;
		add_seg(p.x, R);
	}
	rev.insert(q);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("C.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	int m;
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; i++) {
		nxt[i] = n+1;
		rt[i] = (i-1)/M+1;
	}
	for(int i=1; i<=n; i++) {
		scanf("%d", a+i);
		Insert(pii(i, a[i]));
	}
	for(int typ, x, y; m--;) {
		scanf("%d %d %d", &typ, &x, &y);
		if(typ == 1) {
			Erase(pii(x, a[x]));
			a[x] = y;
			Insert(pii(x, a[x]));
		}else {
			printf("%I64d\n", get(x, y));
		}
	}
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

using INT = long long;

const int NN = 101000;
const int D = 222;

int n, m;
vector<pair<int, int> > cnt[NN];
int nxt[NN], root[NN], a[NN];
set<int> st[NN];

int build(int u) {
	if(u == 0) return 0;
	int L = (u - 1) * D + 1, R = min(n, u * D);
	cnt[u].resize(R-L+1);
	for(int i=L; i<=R; i++) {
		cnt[u][i-L] = {nxt[i], nxt[i] - i};
	}
	sort(cnt[u].begin(), cnt[u].end());
	for(int i=1; i<cnt[u].size(); i++) cnt[u][i].second += cnt[u][i-1].second;
}

INT calc(int L, int R) {
	INT ans = 0;
	for(int i=L; i<=R and root[i] == root[L]; i++) {
		ans += (INT) (nxt[i] - i) * (nxt[i] <= R);
	}
	for(int i=R; root[i] == root[R] and root[i] != root[L]; i--) {
		ans += (INT) (nxt[i] - i) * (nxt[i] <= R);
	}
	for(int i=root[L]+1; i<root[R]; i++) {
		int x = upper_bound(cnt[i].begin(), cnt[i].end(), make_pair(R+1, -1)) - cnt[i].begin();
		if(x == 0) continue; x--;
		ans += cnt[i][x].second;
	}
	return ans;
}

int calc_nxt(int u) {
	if(u == 0) return 0;
	auto it = st[a[u]].upper_bound(u);
	if(it == st[a[u]].end()) return nxt[u] = u;
	return nxt[u] = *it;
}

int calc_pre(int u) {
	if(u == 0) return 0;
	auto it = st[a[u]].lower_bound(u);
	if(it == st[a[u]].begin()) return 0;
	return nxt[*--it] = u, *it;
}

int update(int u, int p) {
	int p1 = calc_pre(u);
	st[a[u]].erase(u); a[u] = p; st[a[u]].insert(u);
	calc_nxt(u); calc_nxt(p1);
	int p2 = calc_pre(u); build(root[p1]);
	if(root[p1] != root[u]) build(root[u]);
	if(root[p2] != root[p1] and root[p2] != root[u]) build(root[p2]);
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
#endif
	cin >> n >> m;
	for(int i=1; i<=n; i++) {
		scanf("%d", a+i);
		root[i] = (D + i - 1) / D;
		st[a[i]].insert(i);
	}
	for(int i=1; i<=n; i++) {
		calc_nxt(i);
	}
	for(int i=1; i<=n; i+=D) {
		build(root[i]);
	}
	for(int i=1; i<=m; i++) {
		int op, L, R;
		scanf("%d %d %d", &op, &L, &R);
		if(op == 1) update(L, R);
		else printf("%I64d\n", calc(L, R));
	}
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#include <iostream>

using namespace std;
typedef long long LL;
const int N = 100010;

struct Node {
	int l, r;
	LL v;
} tree[N * 100];

int n, //number of beads
m, //number of queries
a[N],
treeSize,
nodes[N];
set<int> s[N];

void segmentUpdate(int &si, int ss, int se, int i, int diff) {
	if (i < ss || i > se) {
		return;
	}

	if (!si) {
		++treeSize;
		si = treeSize;
	}

	tree[si].v += diff;
	if (ss != se) {
		int mid = ss + se >> 1;
		segmentUpdate(tree[si].r, mid + 1, se, i, diff);
		segmentUpdate(tree[si].l, ss, mid, i, diff);
	}

	cout << "";
}

void fenwickUpdate(int si, int prevPos, int delta) {
	while (si <= n) {
		segmentUpdate(nodes[si], 1, n, prevPos, delta);
		si += si & -si; //getting next element to modify
	}
	cout << "";
}

void doInsert(int pos, int x) {

	s[x].insert(pos);

	auto refPos = s[x].find(pos);
	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		fenwickUpdate(pos, prevPos, pos - prevPos);
	}

	if (nextPos) {
		fenwickUpdate(nextPos, pos, nextPos - pos);
	}

	if (prevPos && nextPos) {
		fenwickUpdate(nextPos, prevPos, prevPos - nextPos);
	}

	cout << "";
}

void doDelete(int pos, int x) {
	auto refPos = s[x].find(pos);

	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		fenwickUpdate(pos, prevPos, prevPos - pos);
	}

	if (nextPos) {
		fenwickUpdate(nextPos, pos, pos - nextPos);
	}

	if (prevPos && nextPos) {
		fenwickUpdate(nextPos, prevPos, nextPos - prevPos);
	}

	s[x].erase(pos);
	cout << "";
}

LL segmentQuery(int si, int sl, int sr, int ql, int qr) {
	if (ql <= sl && sr <= qr) {
		return tree[si].v;
	}
	if (sl>qr || ql>sr) {
		return 0;
	}
	int mid = sl + sr >> 1;
	return segmentQuery(tree[si].l, sl, mid, ql, qr) + segmentQuery(tree[si].r, mid + 1, sr, ql, qr);
}

LL fenwickQuery(int index, int ql, int qr, LL ret = 0) {
	while (index) {
		ret += segmentQuery(nodes[index], 1, n, ql, qr);
		index -= index & -index; //get parent index of element
	}
	return ret;
}

int main() {
	scanf("%d%d", &n, &m);

	for (int i = 1; i <= n; ++i) {
		scanf("%d", a + i);
		doInsert(i, a[i]);
	}

	for (int i = 1, queryType; i <= m; ++i) {
		scanf("%d", &queryType);

		//update query
		if (queryType == 1) {
			int p, x;
			scanf("%d%d", &p, &x);
			doDelete(p, a[p]);
			a[p] = x;
			doInsert(p, x);
		}

		//make select query
		if (queryType == 2) {
			int ql, qr;
			scanf("%d%d", &ql, &qr);
			printf("%I64d\n", fenwickQuery(qr, ql, qr));
		}

	}

	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#include <iostream>

using namespace std;
typedef long long LL;
const int N = 100010;

struct Node {
	int l, r;
	LL v;
} segments[N * 100];

int n, //number of beads
m, //number of queries
a[N],
treeSize,
nodes[N];
set<int> s[N];

void Modify(int &t, int l, int r, int prevPos, int delta) {
	if (!t) {
		++treeSize;
		t = treeSize;
	}

	segments[t].v += delta;

	if (l == r) {
		return;
	}

	int mid = l + r >> 1;

	if (prevPos > mid) {
		Modify(segments[t].r, mid + 1, r, prevPos, delta);
	}
	else {
		Modify(segments[t].l, l, mid, prevPos, delta);
	}
	cout << "";
}

void Fenwick_Modify(int index, int prevPos, int delta) {
	while (index <= n) {
		Modify(nodes[index], 1, n, prevPos, delta);
		index += index & -index;
	}
	cout << "";
}

void Insert(int pos, int x) {

	s[x].insert(pos);

	auto refPos = s[x].find(pos);

	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		Fenwick_Modify(pos, prevPos, pos - prevPos);
	}

	if (nextPos) {
		Fenwick_Modify(nextPos, pos, nextPos - pos);
	}

	if (prevPos && nextPos) {
		Fenwick_Modify(nextPos, prevPos, prevPos - nextPos);
	}

	cout << "";
}

void Delete(int pos, int x) {
	auto refPos = s[x].find(pos);

	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		Fenwick_Modify(pos, prevPos, prevPos - pos);
	}

	if (nextPos) {
		Fenwick_Modify(nextPos, pos, pos - nextPos);
	}

	if (prevPos && nextPos) {
		Fenwick_Modify(nextPos, prevPos, nextPos - prevPos);
	}

	s[x].erase(pos);
	cout << "";
}

LL Query(int t, int l, int r, int x, int y) {
	if (!t) {
		return 0;
	}

	if (x <= l && r <= y) {
		return segments[t].v;
	}

	int mid = l + r >> 1;

	LL ret = 0;

	if (x <= mid) {
		ret += Query(segments[t].l, l, mid, x, y);
	}

	if (y > mid) {
		ret += Query(segments[t].r, mid + 1, r, x, y);
	}

	return ret;
}

LL Fenwick_Query(int index, int l, int r, LL ret = 0) {
	while (index) {
		ret += Query(nodes[index], 1, n, l, r);
		index -= index & -index;
	}
	return ret;
}

int main() {
	scanf("%d%d", &n, &m);

	for (int i = 1; i <= n; ++i) {
		scanf("%d", a + i);
		Insert(i, a[i]);
	}

	for (int i = 1, queryType; i <= m; ++i) {
		scanf("%d", &queryType);

		//update query
		if (queryType == 1) {
			int p, x;
			scanf("%d%d", &p, &x);
			Delete(p, a[p]);
			a[p] = x;
			Insert(p, x);
		}

		//make select query
		if (queryType == 2) {
			int l, r;
			scanf("%d%d", &l, &r);
			printf("%I64d\n", Fenwick_Query(r, l, r));
		}

	}

	system("pause");
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#include <iostream>

using namespace std;
typedef long long LL;
const int N = 100010;

struct Node {
	int l, r;
	LL v;
} tree[N * 100];

int n, //number of beads
m, //number of queries
a[N],
treeSize,
nodes[N];
set<int> s[N];

void doModify(int &t, int l, int r, int prevPos, int delta) {
	if (!t) {
		++treeSize;
		t = treeSize;
	}

	tree[t].v += delta;

	if (l == r) {
		return;
	}

	int mid = l + r >> 1;

	if (prevPos > mid) {
		doModify(tree[t].r, mid + 1, r, prevPos, delta);
	}
	else {
		doModify(tree[t].l, l, mid, prevPos, delta);
	}
	cout << "";
}

void fenwickModify(int si, int prevPos, int delta) {
	while (si <= n) {
		doModify(nodes[si], 1, n, prevPos, delta);
		si += si & -si; //getting next element to modify
	}
	cout << "";
}

void doInsert(int pos, int x) {

	s[x].insert(pos);

	auto refPos = s[x].find(pos);
	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		fenwickModify(pos, prevPos, pos - prevPos);
	}

	if (nextPos) {
		fenwickModify(nextPos, pos, nextPos - pos);
	}

	if (prevPos && nextPos) {
		fenwickModify(nextPos, prevPos, prevPos - nextPos);
	}

	cout << "";
}

void doDelete(int pos, int x) {
	auto refPos = s[x].find(pos);

	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		fenwickModify(pos, prevPos, prevPos - pos);
	}

	if (nextPos) {
		fenwickModify(nextPos, pos, pos - nextPos);
	}

	if (prevPos && nextPos) {
		fenwickModify(nextPos, prevPos, nextPos - prevPos);
	}

	s[x].erase(pos);
	cout << "";
}

LL doQuery(int si, int sl, int sr, int ql, int qr) {
	if (!si) {
		return 0;
	}

	if (ql <= sl && sr <= qr) {
		return tree[si].v;
	}

	int mid = sl + sr >> 1;

	LL ret = 0;

	if (ql <= mid) {
		ret += doQuery(tree[si].l, sl, mid, ql, qr);
	}

	if (qr > mid) {
		ret += doQuery(tree[si].r, mid + 1, sr, ql, qr);
	}

	return ret;
}

LL fenwickQuery(int index, int ql, int qr, LL ret = 0) {
	while (index) {
		ret += doQuery(nodes[index], 1, n, ql, qr);
		index -= index & -index; //get parent index of element
	}
	return ret;
}

int main() {
	scanf("%d%d", &n, &m);

	for (int i = 1; i <= n; ++i) {
		scanf("%d", a + i);
		doInsert(i, a[i]);
	}

	for (int i = 1, queryType; i <= m; ++i) {
		scanf("%d", &queryType);

		//update query
		if (queryType == 1) {
			int p, x;
			scanf("%d%d", &p, &x);
			doDelete(p, a[p]);
			a[p] = x;
			doInsert(p, x);
		}

		//make select query
		if (queryType == 2) {
			int ql, qr;
			scanf("%d%d", &ql, &qr);
			printf("%I64d\n", fenwickQuery(qr, ql, qr));
		}

	}

	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#include <iostream>

using namespace std;
typedef long long LL;
const int N = 100010;

struct Node {
	int l, r;
	LL v;
} tree[N * 100];

int n, //number of beads
m, //number of queries
a[N],
treeSize,
nodes[N];
set<int> s[N];

void doModify(int &t, int l, int r, int prevPos, int delta) {
	if (!t) {
		++treeSize;
		t = treeSize;
	}

	tree[t].v += delta;

	if (l == r) {
		return;
	}

	int mid = l + r >> 1;

	if (prevPos > mid) {
		doModify(tree[t].r, mid + 1, r, prevPos, delta);
	}
	else {
		doModify(tree[t].l, l, mid, prevPos, delta);
	}
	cout << "";
}

void fenwickModify(int si, int prevPos, int delta) {
	while (si <= n) {
		doModify(nodes[si], 1, n, prevPos, delta);
		si += si & -si; //getting next element to modify
	}
	cout << "";
}

void doInsert(int pos, int x) {

	s[x].insert(pos);

	auto refPos = s[x].find(pos);
	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		fenwickModify(pos, prevPos, pos - prevPos);
	}

	if (nextPos) {
		fenwickModify(nextPos, pos, nextPos - pos);
	}

	if (prevPos && nextPos) {
		fenwickModify(nextPos, prevPos, prevPos - nextPos);
	}

	cout << "";
}

void doDelete(int pos, int x) {
	auto refPos = s[x].find(pos);

	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		fenwickModify(pos, prevPos, prevPos - pos);
	}

	if (nextPos) {
		fenwickModify(nextPos, pos, pos - nextPos);
	}

	if (prevPos && nextPos) {
		fenwickModify(nextPos, prevPos, nextPos - prevPos);
	}

	s[x].erase(pos);
	cout << "";
}

LL doQuery(int si, int sl, int sr, int ql, int qr) {
	if (ql <= sl && sr <= qr) {
		return tree[si].v;
	}
	if (sl>qr || ql>sr) {
		return 0;
	}
	int mid = sl + sr >> 1;
	return doQuery(tree[si].l, sl, mid, ql, qr) + doQuery(tree[si].r, mid + 1, sr, ql, qr);
	//LL ret = 0;

	//if (ql <= mid) {
	//	ret += doQuery(tree[si].l, sl, mid, ql, qr);
	//}

	//if (qr > mid) {
	//	ret += doQuery(tree[si].r, mid + 1, sr, ql, qr);
	//}

	//return ret;
}

LL fenwickQuery(int index, int ql, int qr, LL ret = 0) {
	while (index) {
		ret += doQuery(nodes[index], 1, n, ql, qr);
		index -= index & -index; //get parent index of element
	}
	return ret;
}

int main() {
	scanf("%d%d", &n, &m);

	for (int i = 1; i <= n; ++i) {
		scanf("%d", a + i);
		doInsert(i, a[i]);
	}

	for (int i = 1, queryType; i <= m; ++i) {
		scanf("%d", &queryType);

		//update query
		if (queryType == 1) {
			int p, x;
			scanf("%d%d", &p, &x);
			doDelete(p, a[p]);
			a[p] = x;
			doInsert(p, x);
		}

		//make select query
		if (queryType == 2) {
			int ql, qr;
			scanf("%d%d", &ql, &qr);
			printf("%I64d\n", fenwickQuery(qr, ql, qr));
		}

	}

	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#include <iostream>

using namespace std;
typedef long long LL;
const int N = 100010;

struct Node {
	int l, r;
	LL v;
} tree[N * 100];

int n, //number of beads
m, //number of queries
a[N],
treeSize,
nodes[N];
set<int> s[N];

void doModify(int &t, int l, int r, int prevPos, int delta) {
	if (!t) {
		++treeSize;
		t = treeSize;
	}

	tree[t].v += delta;

	if (l == r) {
		return;
	}

	int mid = l + r >> 1;

	if (prevPos > mid) {
		doModify(tree[t].r, mid + 1, r, prevPos, delta);
	}
	else {
		doModify(tree[t].l, l, mid, prevPos, delta);
	}
	cout << "";
}

void fenwickModify(int si, int prevPos, int delta) {
	while (si <= n) {
		doModify(nodes[si], 1, n, prevPos, delta);
		si += si & -si; //getting next element to modify
	}
	cout << "";
}

void doInsert(int pos, int x) {

	s[x].insert(pos);

	auto refPos = s[x].find(pos);
	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		fenwickModify(pos, prevPos, pos - prevPos);
	}

	if (nextPos) {
		fenwickModify(nextPos, pos, nextPos - pos);
	}

	if (prevPos && nextPos) {
		fenwickModify(nextPos, prevPos, prevPos - nextPos);
	}

	cout << "";
}

void doDelete(int pos, int x) {
	auto refPos = s[x].find(pos);

	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		fenwickModify(pos, prevPos, prevPos - pos);
	}

	if (nextPos) {
		fenwickModify(nextPos, pos, pos - nextPos);
	}

	if (prevPos && nextPos) {
		fenwickModify(nextPos, prevPos, nextPos - prevPos);
	}

	s[x].erase(pos);
	cout << "";
}

LL doQuery(int si, int sl, int sr, int ql, int qr) {
	if (ql <= sl && sr <= qr) {
		return tree[si].v;
	}
	if (sl>qr || ql>sr) {
		return 0;
	}
	int mid = sl + sr >> 1;
	return doQuery(tree[si].l, sl, mid, ql, qr) + doQuery(tree[si].r, mid + 1, sr, ql, qr);
	//LL ret = 0;

	//if (ql <= mid) {
	//	ret += doQuery(tree[si].l, sl, mid, ql, qr);
	//}

	//if (qr > mid) {
	//	ret += doQuery(tree[si].r, mid + 1, sr, ql, qr);
	//}

	//return ret;
}

LL fenwickQuery(int index, int ql, int qr, LL ret = 0) {
	while (index) {
		ret += doQuery(nodes[index], 1, n, ql, qr);
		index -= index & -index; //get parent index of element
	}
	return ret;
}

int main() {
	scanf("%d%d", &n, &m);

	for (int i = 1; i <= n; ++i) {
		scanf("%d", a + i);
		doInsert(i, a[i]);
	}

	for (int i = 1, queryType; i <= m; ++i) {
		scanf("%d", &queryType);

		//update query
		if (queryType == 1) {
			int p, x;
			scanf("%d%d", &p, &x);
			doDelete(p, a[p]);
			a[p] = x;
			doInsert(p, x);
		}

		//make select query
		if (queryType == 2) {
			int ql, qr;
			scanf("%d%d", &ql, &qr);
			printf("%I64d\n", fenwickQuery(qr, ql, qr));
		}

	}

	system("pause");
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#include <iostream>

using namespace std;
typedef long long LL;
const int N = 100010;

struct Node {
	int l, r;
	LL v;
} segments[N * 100];

int n, //number of beads
m, //number of queries
a[N],
treeSize,
nodes[N];
set<int> s[N];

void Modify(int &t, int l, int r, int prevPos, int delta) {
	if (!t) {
		++treeSize;
		t = treeSize;
	}

	segments[t].v += delta;

	if (l == r) {
		return;
	}

	int mid = l + r >> 1;

	if (prevPos > mid) {
		Modify(segments[t].r, mid + 1, r, prevPos, delta);
	}
	else {
		Modify(segments[t].l, l, mid, prevPos, delta);
	}
	cout << "";
}

void Fenwick_Modify(int index, int prevPos, int delta) {
	while (index <= n) {
		Modify(nodes[index], 1, n, prevPos, delta);
		index += index & -index;
	}
	cout << "";
}

void Insert(int pos, int x) {

	s[x].insert(pos);

	auto refPos = s[x].find(pos);

	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		Fenwick_Modify(pos, prevPos, pos - prevPos);
	}

	if (nextPos) {
		Fenwick_Modify(nextPos, pos, nextPos - pos);
	}

	if (prevPos && nextPos) {
		Fenwick_Modify(nextPos, prevPos, prevPos - nextPos);
	}

	cout << "";
}

void Delete(int pos, int x) {
	auto refPos = s[x].find(pos);

	auto refNextPos = refPos;
	refNextPos++;

	int prevPos = 0, nextPos = 0;

	if (refPos != s[x].begin()) {
		prevPos = *(--refPos);
	}

	if (refNextPos != s[x].end()) {
		nextPos = *refNextPos;
	}

	if (prevPos) {
		Fenwick_Modify(pos, prevPos, prevPos - pos);
	}

	if (nextPos) {
		Fenwick_Modify(nextPos, pos, pos - nextPos);
	}

	if (prevPos && nextPos) {
		Fenwick_Modify(nextPos, prevPos, nextPos - prevPos);
	}

	s[x].erase(pos);
	cout << "";
}

LL Query(int t, int l, int r, int x, int y) {
	if (!t) {
		return 0;
	}

	if (x <= l && r <= y) {
		return segments[t].v;
	}

	int mid = l + r >> 1;

	LL ret = 0;

	if (x <= mid) {
		ret += Query(segments[t].l, l, mid, x, y);
	}

	if (y > mid) {
		ret += Query(segments[t].r, mid + 1, r, x, y);
	}

	return ret;
}

LL Fenwick_Query(int index, int l, int r, LL ret = 0) {
	while (index) {
		ret += Query(nodes[index], 1, n, l, r);
		index -= index & -index;
	}
	return ret;
}

int main() {
	scanf("%d%d", &n, &m);

	for (int i = 1; i <= n; ++i) {
		scanf("%d", a + i);
		Insert(i, a[i]);
	}

	for (int i = 1, queryType; i <= m; ++i) {
		scanf("%d", &queryType);

		//update query
		if (queryType == 1) {
			int p, x;
			scanf("%d%d", &p, &x);
			Delete(p, a[p]);
			a[p] = x;
			Insert(p, x);
		}

		//make select query
		if (queryType == 2) {
			int l, r;
			scanf("%d%d", &l, &r);
			printf("%I64d\n", Fenwick_Query(r, l, r));
		}

	}

	//system("pause");
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

typedef long long int64;

struct DinamicBinaryIndexedTree
{
  map< int, int > data;

  int64 sum(int k)
  {
    int64 ret = 0;
    for(++k; k <= 100010; k += k & -k) {
      if(data.count(k)) ret += data[k];
    }
    return (ret);
  }

  void add(int k, int64 x)
  {
    for(++k; k > 0; k -= k & -k) {
      data[k] += x;
    }
  }

};

struct SegmentTree
{
  int sz;
  vector< DinamicBinaryIndexedTree > seg;

  SegmentTree(int n)
  {
    sz = 1;
    while(sz < n) sz <<= 1;
    seg.resize(2 * sz - 1);
  }

  void update(int x, int y, int64 z)
  {
    x += sz - 1;
    seg[x].add(y, z);
    while(x > 0) {
      x = (x - 1) >> 1;
      seg[x].add(y, z);
    }
  }

  int64 query(int a, int b, int k, int l, int r)
  {
    if(a >= r || b <= l) return (0);
    if(a <= l && r <= b) return (seg[k].sum(a));
    return (query(a, b, 2 * k + 1, l, (l + r) >> 1) + query(a, b, 2 * k + 2, (l + r) >> 1, r));
  }

  int64 query(int a, int b)
  {
    return (query(a, b, 0, 0, sz));
  }
};

int main()
{
  int N, M, A[100000];
  set< int > st[100001];

  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    st[A[i]].emplace(i);
  }
  for(int i = 1; i <= N; i++) st[i].emplace(N);

  SegmentTree seg(N + 1);
  for(int i = 0; i < N; i++) {
    auto it = st[A[i]].lower_bound(i);
    if(it != begin(st[A[i]])) seg.update(*it, *prev(it), *it - *prev(it));
  }

  for(int i = 0; i < M; i++) {
    int T, X, Y;
    scanf("%d %d %d", &T, &X, &Y);
    --X;
    if(T == 1) {
      auto it = st[A[X]].lower_bound(X);
      if(it != begin(st[A[X]])) seg.update(*it, *prev(it), *prev(it) - *it);
      seg.update(*next(it), *it, *it - *next(it));
      it = st[A[X]].erase(it);
      seg.update(*it, *prev(it), *it - *prev(it));

      A[X] = Y;
      it = st[A[X]].lower_bound(X);
      if(it != begin(st[A[X]])) seg.update(*it, *prev(it), *prev(it) - *it);
      st[A[X]].emplace(X);
      it = st[A[X]].lower_bound(X);
      if(it != begin(st[A[X]])) seg.update(*it, *prev(it), *it - *prev(it));
      ++it;
      seg.update(*it, *prev(it), *it - *prev(it));
    } else {
      printf("%lld\n", seg.query(X, Y));
    }
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (first[A[idx]] != -1 && idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (last[A[idx]] != -1 && idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(init_nt[idx] != -1 && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    assert(init_nt[idx] != -1 || init_nt[idx] >= nr);
    if(init_pv[idx] != -1 && nl <= init_pv[idx]) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(nl <= init_pv[idx] && init_pv[idx] < nr) {
      first[A[idx]] = init_pv[idx];
      ans -= first[A[idx]];
      throw (0);
    } else if(nl <= init_nt[idx] && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(nl <= init_nt[idx] && init_nt[idx] < nr) {
      last[A[idx]] = init_nt[idx];
      ans += last[A[idx]];
      throw(0);
    } else if(nl <= init_pv[idx] && init_pv[idx] < nr) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(nl <= init_pv[idx] && init_pv[idx] < nr) {
      first[A[idx]] = init_pv[idx];
      ans -= first[A[idx]];
   //   throw (0);
    } else if(nl <= init_nt[idx] && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(nl <= init_nt[idx] && init_nt[idx] < nr) {
      last[A[idx]] = init_nt[idx];
      ans += last[A[idx]];
      throw(0);
    } else if(nl <= init_pv[idx] && init_pv[idx] < nr) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (first[A[idx]] != -1 && idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (last[A[idx]] != -1 && idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(init_nt[idx] != -1 && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(init_pv[idx] != -1 && nl <= init_pv[idx]) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(init_nt[idx] != -1 && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(init_pv[idx] != -1 && nl <= init_pv[idx]) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(nl <= init_pv[idx]) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100005], buff[100005];

set< int > line[100005];
int init_pv[100005], init_nt[100005];
int X[100005], Y[100005], Z[100005];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (first[A[idx]] != -1 && idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (last[A[idx]] != -1 && idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(init_pv[idx] != -1 && nl <= init_pv[idx]) {
      first[A[idx]] = init_pv[idx];
      ans -= first[A[idx]];
    } else if(init_nt[idx] != -1 && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(init_nt[idx] != -1 && init_nt[idx] < nr) {
      last[A[idx]] = init_nt[idx];
      ans += last[A[idx]];
    } else if(init_pv[idx] != -1 && nl <= init_pv[idx]) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include<bits/stdc++.h>

using namespace std;

typedef long long int64;

struct DinamicBinaryIndexedTree
{
  map< int, int64 > data;

  int64 sum(int k)
  {
    int64 ret = 0;
    for(++k; k <= 100010; k += k & -k) {
      if(data.count(k)) ret += data[k];
    }
    return (ret);
  }

  void add(int k, int64 x)
  {
    for(++k; k > 0; k -= k & -k) {
      data[k] += x;
    }
  }

};

struct SegmentTree
{
  int sz;
  vector< DinamicBinaryIndexedTree > seg;

  SegmentTree(int n)
  {
    sz = 1;
    while(sz < n) sz <<= 1;
    seg.resize(2 * sz - 1);
  }

  void update(int x, int y, int64 z)
  {
    x += sz - 1;
    seg[x].add(y, z);
    while(x > 0) {
      x = (x - 1) >> 1;
      seg[x].add(y, z);
    }
  }

  int64 query(int a, int b, int k, int l, int r)
  {
    if(a >= r || b <= l) return (0);
    if(a <= l && r <= b) return (seg[k].sum(a));
    return (query(a, b, 2 * k + 1, l, (l + r) >> 1) + query(a, b, 2 * k + 2, (l + r) >> 1, r));
  }

  int64 query(int a, int b)
  {
    return (query(a, b, 0, 0, sz));
  }
};

int main()
{
  int N, M, A[100000];
  set< int > st[100001];

  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    st[A[i]].emplace(i);
  }
  for(int i = 1; i <= N; i++) st[i].emplace(N);

  SegmentTree seg(N + 1);
  for(int i = 0; i < N; i++) {
    auto it = st[A[i]].lower_bound(i);
    if(it != begin(st[A[i]])) seg.update(*it, *prev(it), *it - *prev(it));
  }

  for(int i = 0; i < M; i++) {
    int T, X, Y;
    scanf("%d %d %d", &T, &X, &Y);
    --X;
    if(T == 1) {
      auto it = st[A[X]].lower_bound(X);
      if(it != begin(st[A[X]])) seg.update(*it, *prev(it), *prev(it) - *it);
      seg.update(*next(it), *it, *it - *next(it));
      it = st[A[X]].erase(it);
      if(it != begin(st[A[X]]) seg.update(*it, *prev(it), *it - *prev(it));

      A[X] = Y;
      it = st[A[X]].lower_bound(X);
      if(it != begin(st[A[X]])) seg.update(*it, *prev(it), *prev(it) - *it);
      st[A[X]].emplace(X);
      it = st[A[X]].lower_bound(X);
      if(it != begin(st[A[X]])) seg.update(*it, *prev(it), *it - *prev(it));
      ++it;
      seg.update(*it, *prev(it), *it - *prev(it));
    } else {
      printf("%lld\n", seg.query(X, Y));
    }
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(nl <= init_pv[idx] && init_pv[idx] < nr) {
      first[A[idx]] = init_pv[idx];
      ans -= first[A[idx]];
      throw (0);
    } else if(nl <= init_nt[idx] && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(nl <= init_nt[idx] && init_nt[idx] < nr) {
      last[A[idx]] = init_nt[idx];
      ans += last[A[idx]];
      //throw(0);
    } else if(nl <= init_pv[idx] && init_pv[idx] < nr) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100005], buff[100005];

set< int > line[100005];
int init_pv[100005], init_nt[100005];
int X[100005], Y[100005], Z[100005];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (first[A[idx]] != -1 && idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (last[A[idx]] != -1 && idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(init_nt[idx] != -1 && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(init_pv[idx] != -1 && nl <= init_pv[idx]) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(A[Y[idx]] == Z[idx]) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width(2000), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100005], buff[100005];

set< int > line[100005];
int init_pv[100005], init_nt[100005];
int X[100005], Y[100005], Z[100005];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (first[A[idx]] != -1 && idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (last[A[idx]] != -1 && idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(init_nt[idx] != -1 && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(init_pv[idx] != -1 && nl <= init_pv[idx]) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(A[Y[idx]] == Z[idx]) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], ZZ[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001], ans;

int ret[100001];

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(nl <= init_pv[idx] && init_pv[idx] < nr) {
      first[A[idx]] = init_pv[idx];
      ans -= first[A[idx]];
    } else if(nl <= init_nt[idx] && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    if(nl <= init_nt[idx] && init_nt[idx] < nr) {
      last[A[idx]] = init_nt[idx];
      ans += last[A[idx]];
    } else if(nl <= init_pv[idx] && init_pv[idx] < nr) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%d\n", ret[i]);
  }
}


#include <bits/stdc++.h>

using namespace std;

struct Mo_3D
{
  vector< int > left, right, index, order;
  vector< bool > v;
  int width;
  int nl, nr, time, ptr;

  Mo_3D(int n) : width((int) pow(n, 2.0 / 3.0)), nl(0), nr(0), ptr(0), time(0), v(n) {}

  void insert(int idx, int l, int r) /* [l, r) */
  {
    left.push_back(l);
    right.push_back(r);
    index.push_back(idx);
  }

  void build()
  {
    order.resize(left.size());
    iota(begin(order), end(order), 0);
    sort(begin(order), end(order), [&](int a, int b)
    {
      if(left[a] / width != left[b] / width) return left[a] < left[b];
      if(right[a] / width != right[b] / width) return bool((right[a] < right[b]) ^ (left[a] / width % 2));
      return bool((index[a] < index[b]) ^ (right[a] / width % 2));
    });
  }

  int process()
  {
    if(ptr == order.size()) return (-1);
    const auto id = order[ptr];
    while(time < index[id]) addquery(time++);
    while(time > index[id]) delquery(--time);
    while(nl > left[id]) distribute(--nl);
    while(nr < right[id]) distribute(nr++);
    while(nl < left[id]) distribute(nl++);
    while(nr > right[id]) distribute(--nr);
    return (index[order[ptr++]]);
  }

  inline void distribute(int idx)
  {
    v[idx].flip();
    if(v[idx]) add(idx);
    else del(idx);
  }

  void add(int idx);

  void del(int idx);

  void addquery(int idx);

  void delquery(int idx);
};

typedef long long int64;

int N, M, A[100000], buff[100000];

set< int > line[100001];
int init_pv[100000], init_nt[100000];
int X[100000], Y[100000], Z[100000];

vector< pair< int, int > > update_pv[100000], update_nt[100000];
int first[100001], last[100001];

int64 ret[100001], ans;

void Mo_3D::add(int idx)
{
  if(first[A[idx]] == -1 || (first[A[idx]] != -1 && idx < first[A[idx]])) {
    if(first[A[idx]] != -1) ans += first[A[idx]];
    ans -= idx;
    first[A[idx]] = idx;
  }
  if(last[A[idx]] == -1 || (last[A[idx]] != -1 && idx > last[A[idx]])) {
    if(last[A[idx]] != -1) ans -= last[A[idx]];
    ans += idx;
    last[A[idx]] = idx;
  }
}

void Mo_3D::del(int idx)
{
  if(first[A[idx]] == idx) {
    ans += idx;
    if(init_nt[idx] != -1 && init_nt[idx] < nr) {
      first[A[idx]] = init_nt[idx];
      ans -= first[A[idx]];
    } else {
      first[A[idx]] = -1;
    }
  }
  if(last[A[idx]] == idx) {
    ans -= idx;
    assert(init_nt[idx] == -1 || init_nt[idx] >= nr);
    if(init_pv[idx] != -1 && nl <= init_pv[idx]) {
      last[A[idx]] = init_pv[idx];
      ans += last[A[idx]];
    } else {
      last[A[idx]] = -1;
    }
  }
}

void Mo_3D::addquery(int idx)
{
  if(X[idx] == 2) return;

  if(v[Y[idx]]) {
    distribute(Y[idx]);
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
    distribute(Y[idx]);
  } else {
    for(auto &q : update_pv[idx]) swap(init_pv[q.first], q.second);
    for(auto &q : update_nt[idx]) swap(init_nt[q.first], q.second);
    swap(A[Y[idx]], Z[idx]);
  }
}

void Mo_3D::delquery(int idx)
{
  addquery(idx);
}

int main()
{
  scanf("%d %d", &N, &M);
  for(int i = 0; i < N; i++) {
    scanf("%d", &A[i]);
    line[A[i]].emplace(i);
    buff[i] = A[i];
  }
  for(int i = 0; i < M; i++) {
    scanf("%d %d %d", &X[i], &Y[i], &Z[i]);
    --Y[i];
  }

  memset(init_pv, -1, sizeof(init_pv));
  memset(init_nt, -1, sizeof(init_nt));
  for(int i = 0; i < N; i++) {
    auto p = line[A[i]].lower_bound(i);
    if(p != begin(line[A[i]])) init_pv[i] = *prev(p);
    if(next(p) != end(line[A[i]])) init_nt[i] = *next(p);
  }

  Mo_3D mo(N);
  for(int i = 0; i < M; i++) {

    if(X[i] == 1) {
      {
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, nt);
        if(~nt) update_pv[i].emplace_back(nt, pv);
        line[A[Y[i]]].erase(Y[i]);
      }
      {
        A[Y[i]] = Z[i];
        line[A[Y[i]]].emplace(Y[i]);
        auto p = line[A[Y[i]]].lower_bound(Y[i]);
        const int pv = (p != begin(line[A[Y[i]]]) ? *prev(p) : -1);
        const int nt = (next(p) != end(line[A[Y[i]]]) ? *next(p) : -1);
        if(~pv) update_nt[i].emplace_back(pv, Y[i]);
        if(~nt) update_pv[i].emplace_back(nt, Y[i]);
        update_pv[i].emplace_back(Y[i], pv);
        update_nt[i].emplace_back(Y[i], nt);
      }
    } else {
      mo.insert(i, Y[i], Z[i]);
    }
  }

  mo.build();

  int id;
  memset(first, -1, sizeof(first));
  memset(last, -1, sizeof(last));
  for(int i = 0; i < N; i++) A[i] = buff[i];
  while((id = mo.process()) != -1) ret[id] = ans;

  for(int i = 0; i < M; i++) {
    if(X[i] == 2) printf("%lld\n", ret[i]);
  }
}