bzoj2120: 数颜色
妈也第三次补莫队。。。
好吧大概是以后不用补了。
讲一讲,首先操作就是离线,把询问和修改记录下来,特别要注意的,询问要记录该询问前有多少个修改ti,修改要记录修改前的颜色pre。
第二步就是分块,然后按l,r,ti块的顺序排序
然后这个暴力怎么写呢。
主要的思想就是将当前的延伸到要求的。带修就是三维l,r,T了。
假设当前求出了一个询问,那么l,r,T,都等于这个询问的值,按顺序要求新询问
那么按照T,l,r的顺序,暴力恢复到满足三个条件就可以了。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int n,m,a[11000]; struct query { int l,r,ti,id; }q[11000];int qlen; struct change_color { int ip,now,pre;//pre记录这个修改前的颜色 }c[11000];int clen,last[11000];//last是最后的颜色 int block,st[11000]; bool cmp(query n1,query n2) { if((st[n1.l]<st[n2.l]) || (st[n1.l]==st[n2.l]&&st[n1.r]<st[n2.r]) || (st[n1.l]==st[n2.l]&&st[n1.r]==st[n2.r]&&st[n1.ti]<st[n2.ti])) return true; return false; } int as[11000]; int col[1100000],ans; void change(int x,int k) { col[x]+=k; if(k==-1&&col[x]==0)ans--; if(k==1&&col[x]==1)ans++; } void solve() { int l=1,r=0,T=0; for(int i=1;i<=qlen;i++) { while(T<q[i].ti) { T++; if(l<=c[T].ip&&c[T].ip<=r)//释放对答案的影响 change(a[c[T].ip],-1), change(c[T].now,1); a[c[T].ip]=c[T].now;//位置的颜色更改 }//时间加速 while(T>q[i].ti) { if(l<=c[T].ip&&c[T].ip<=r) change(a[c[T].ip],-1), change(c[T].pre,1); a[c[T].ip]=c[T].pre; T--; }//时间倒流 //ti while(l<q[i].l)change(a[l],-1), l++; while(l>q[i].l)l--, change(a[l],1); while(r<q[i].r)r++, change(a[r],1); while(r>q[i].r)change(a[r],-1), r--; //l&r as[q[i].id]=ans; } } char ss[20]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]), last[i]=a[i]; int x,y; for(int i=1;i<=m;i++) { scanf("%s%d%d",ss+1,&x,&y); if(ss[1]=='Q') { qlen++; q[qlen].l=x;q[qlen].r=y; q[qlen].ti=clen;q[qlen].id=qlen; }//qins else if(ss[1]=='R') { clen++; c[clen].ip=x;c[clen].now=y; c[clen].pre=last[x];last[x]=y; }//cins } //离线 block=int(pow(n,0.66666)); for(int i=1;i<=n;i++)st[i]=(i-1)/block+1; sort(q+1,q+qlen+1,cmp); ans=0; solve(); for(int i=1;i<=qlen;i++)printf("%d\n",as[i]); return 0; }
pain and happy in the cruel world.