带修莫队的做法:
把所有修改也离线下来
新建一个tk指针表示进行了k次修改,然后对于每个询问记录一下它之前有多少次修改,记为k,处理这个询问时如果当前修改次数小于k,那么就把tk往上滚,并进行修改,如果大于k,就把tk往下滚,并回溯修改
Code:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=10005;
int pos[N],last[N];
int n,m,a[N],sqr;
int ans[N],cnt[N];
int cntq,cnto;
struct Q{int l,r,id,k;}q[N];
struct Op{int x,y,z;}op[N];
inline bool cmp(Q a,Q b){
if(pos[a.l]!=pos[b.l]) return pos[a.l]<pos[b.l];
else if(pos[a.r]!=pos[b.r]) return pos[a.r]<pos[b.r];
return a.k<b.k;
}
char ss;
int main(){
n=read(),m=read();sqr=pow(n,2.0/3);
for(int i=1;i<=n;i++) last[i]=a[i]=read();
for(int i=1;i<=n;i++) pos[i]=(i-1)/sqr+1;
for(int x,y,i=1;i<=m;i++){
scanf("%c",&ss);x=read(),y=read();
if(ss=='R') op[++cnto].x=x,op[cnto].y=y,op[cnto].z=last[x],last[x]=y;
else q[++cntq].l=x,q[cntq].r=y,q[cntq].id=cntq,q[cntq].k=cnto;
}
sort(q+1,q+cntq+1,cmp);
int tl=0,tr=0,tk=0,tot=0;
for(int i=1;i<=cntq;i++){
int l=q[i].l,r=q[i].r;
while(tk<q[i].k){
++tk;
if(tl<=op[tk].x && op[tk].x<=tr){
if(!--cnt[a[op[tk].x]]) --tot;
if(!cnt[op[tk].y]++) ++tot;
}
a[op[tk].x]=op[tk].y;
}
while(tk>q[i].k){
if(tl<=op[tk].x && op[tk].x<=tr){
if(!--cnt[a[op[tk].x]]) --tot;
if(!cnt[op[tk].z]++) ++tot;
}
a[op[tk].x]=op[tk].z;
--tk;
}
while(tl<l) if(!--cnt[a[tl++]]) --tot;
while(tl>l) if(!cnt[a[--tl]]++) ++tot;
while(tr<r) if(!cnt[a[++tr]]++) ++tot;
while(tr>r) if(!--cnt[a[tr--]]) --tot;
ans[q[i].id]=tot;
}
for(int i=1;i<=cntq;i++) cout<<ans[i]<<'\n';
return 0;
}