cdq分治的题 不过要先推出维度的关系
显然想要得出一种数的答案 我们需要知道这种数在区间里面出现的位置 最后的位置减去最前面的位置即可
但是我们无法很便捷的找到最后和最前的位置 却可以找出所有出现的位置
设 pre[i] 为i位置的数上一次出现的位置 对于每一个这样的对(i和pre[i]) 他们的贡献是 i-pre[i]
那么一种数对于整个区间的贡献就是
i<=R pre[i]>=L 的所有贡献和
三个维度分别是 时间,当前位置 i 和pre[i]
对于每一个询问 它的三个维度我们稍微改一下 设置为 时间 R和L
我们加入 i <= R 的所有修改 通过树状数组(下标为pre[i])维护后缀和 询问 >=L 的所有贡献即可
另外我们要用set维护 pre[i]的变化 也就是当p位置修改以后 我们要把修改前的 i和pre[i]的关系进行修改 还要把 i的后继和pre[i]的关系进行修改 修改完以后 也要加入一些关系 (手动模拟一下就懂了)
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
typedef long long ll;
set<int>col[N];
int n,m,val[N],a[N];
struct cd{
int op,p,pr,val,id;
}q[N*10],p[N*10];
int pre[N],tot;
ll c[N],ans[N];
void add(int x,ll val){
while(x){
c[x]+=val;
x-=x&-x;
}
}
ll query(int x){
ll ret = 0;
while(x<=n){
ret+=c[x];
x+=x&-x;
}
return ret;
}
void clear(int x){
while(x){
c[x]=0;
x-=x&-x;
}
}
bool cmp(cd a,cd b){
return a.p<b.p;
}
void cdq(int L,int R){
if(L==R) return;
int M = L+R>>1;
cdq(L,M);cdq(M+1,R);
int j = L,c = L;
for(int i = M+1; i <= R; i++){
while(j<=M&&q[j].p<=q[i].p){
if(q[j].op==1) add(q[j].pr,q[j].val);
p[c++]=q[j++];
}
if(q[i].op==2) ans[q[i].id]+=query(q[i].pr);
p[c++]=q[i];
}
for(int i = L; i < j; i++) if(q[i].op==1) clear(q[i].pr);
for(int i = j; i <= M; i++) p[c++]=q[i];
for(int i = L; i < c; i++) q[i]=p[i];
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
if(col[a[i]].empty()) pre[i]=0; else pre[i]=*--col[a[i]].end();
col[a[i]].insert(i);
q[++tot]=(cd){1,i,pre[i],i-pre[i],0};
}
for(int i = 1; i <= n; i++) col[i].insert(0);
int qt = 0;
for(int i = 1; i <= m; i++){
int op,x,y,nex;
scanf("%d%d%d",&op,&x,&y);
if(op==1){
q[++tot]=(cd){op,x,pre[x],pre[x]-x,0};
if(++col[a[x]].lower_bound(x)!=col[a[x]].end()){
nex = *++col[a[x]].lower_bound(x);
q[++tot]=(cd){op,nex,pre[nex],pre[nex]-nex,0};
pre[nex]=pre[x];
q[++tot]=(cd){op,nex,pre[nex],nex-pre[nex],0};
}
col[a[x]].erase(x);a[x]=y;
col[a[x]].insert(x);pre[x]=*--col[a[x]].lower_bound(x);
q[++tot]=(cd){op,x,pre[x],x-pre[x],0};
if(++col[a[x]].lower_bound(x)!=col[a[x]].end()){
nex = *++col[a[x]].lower_bound(x);
q[++tot]=(cd){op,nex,pre[nex],pre[nex]-nex,0};
pre[nex]=x;
q[++tot]=(cd){op,nex,pre[nex],nex-pre[nex],0};
}
}else{
q[++tot]=(cd){op,y,x,0,++qt};
}
}
cdq(1,tot);
for(int i = 1; i <= qt; i++) printf("%lld\n",ans[i]);
return 0;
}