裸的带修莫队。
在Sort时如果左右区间都在同一块中,就按询问的修改的先后Sort。
对于每次查询判断向前或向后修改。
当size为N*2/3时据说是最优。O(N^(3/5))。
code:
/************************************************************** Problem: 2120 User: yekehe Language: C++ Result: Accepted Time:884 ms Memory:5652 kb ****************************************************************/ #include <cmath> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; inline char tc(void){ static char fl[10000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,10000,stdin),A==B)?EOF:*A++; } int read() { char c;while(c=tc(),c<'0'||c>'9'); int x=c-'0';while(c=tc(),c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0'; return x; } int N,M,size,a[10005],D[10005],Be[10005],ans,sum[1000005],A[10005],l,r,t; struct Query{int l,r,tim,id;}Q[10005];int Qs; struct Change{int x,bef,to;}C[10005];int Cs; int cmp(Query x,Query y){ return Be[x.l]==Be[y.l]? (Be[x.r]==Be[y.r]?x.tim<y.tim:x.r<y.r) :x.l<y.l; }//CMP函数 void re(int x,int d){ sum[x]+=d; if(!sum[x]&&d<0)ans--; if(sum[x]==1&&d>0)ans++; } int ct(int x,int y){ if(l<=x&&x<=r)re(a[x],-1),re(y,1); a[x]=y; } int main() { N=read(),M=read(); for(int i=1;i<=N;i++)a[i]=read(),D[i]=a[i]; int x,y;char c; for(int i=1;i<=M;i++){ while(c=tc(),c!='Q'&&c!='R'); x=read(),y=read(); if(c=='Q')Q[++Qs]=(Query){x,y,Cs,Qs}; else C[++Cs]=(Change){x,D[x],y},D[x]=y; } size=pow(N,0.66666); for(int i=1;i<=N;i++) Be[i]=(i-1)/size+1; sort(Q+1,Q+Qs+1,cmp); l=1,r=0,t=0; for(int i=1;i<=Qs;i++){ while(t<Q[i].tim)t++,ct(C[t].x,C[t].to);//向后修改 while(t>Q[i].tim)ct(C[t].x,C[t].bef),t--;//向前修改 while(l<Q[i].l)re(a[l],-1),l++; while(l>Q[i].l)re(a[--l],1); while(r<Q[i].r)re(a[++r],1); while(r>Q[i].r)re(a[r],-1),r--; A[Q[i].id]=ans; } for(int i=1;i<=Qs;i++) printf("%d ",A[i]); return 0; }