来自FallDream的博客,未经允许,请勿转载,谢谢
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?
n,m<=10000 修改操作最多1000
貌似是一道暴力都能过的题...233
正解是带修改的莫队,在莫队的基础上,加入修改操作。具体实现就是按照左右端点所在的块排序,左右端点在相同块的按照时间排序,然后在做一个询问的时候把时间修正一下,撤销多做的操作,时间太早就再改一改啥的。这样的话我们把块的数量设成$n^{frac{1}{3}}$最优,复杂度上限$n^{frac{5}{3}}$
但是其实可以直接在线做,还是分成$k=n^{frac{1}{3}}$块,每一个块对开一个数组预处理出答案,预处理$k^{2}n$,然后每次修改直接修改所有包含它的块,复杂度$k^{2}q$,查询找到最接近的块对,然后暴力改剩下的,最后再还原回去,复杂度最大$frac{nq}{k}$。它的空间比较蛋疼....但是如果修改操作比较多或者强制在线,就能体现它的优势啦。
带修改莫队
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define MK 20 #define MN 11000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,s[MN+5],L=1,R=1,T=0,kind=1,f[1000005],cnt1=0,cnt2=0,size,pos[MN+5],l[MN+5],Ans[MN+5]; struct ques{ int last,x,y,lb,rb,time; bool operator<(const ques&b)const{b.lb==lb?(b.rb==rb?(time<b.time):rb<b.rb):lb<b.lb;} }q[MN+5]; struct renew{int x,y,last;}r[MN+5]; char op[15]; inline void Change(int x,int y) { if(L<=x&&x<=R) { if(!--f[s[x]]) --kind; if((++f[y])==1) ++kind; } s[x]=y; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) s[i]=l[i]=read(); size=max((n+MK-1)/MK,1); for(int i=1;i<=m;i++) { scanf("%s",op+1); if(op[1]=='Q') { q[++cnt1].x=read();q[cnt1].y=read(); q[cnt1].lb=(q[cnt1].x-1)/size+1; q[cnt1].rb=(q[cnt1].y-1)/size+1; q[cnt1].time=cnt1;q[cnt1].last=cnt2; } else { r[++cnt2].x=read();r[cnt2].y=read(); r[cnt2].last=l[r[cnt2].x]; l[r[cnt2].x]=r[cnt2].y; } } sort(q+1,q+cnt1+1); f[s[1]]=1; for(int i=1;i<=cnt1;i++) { while(L<q[i].x) if(!--f[s[L++]]) --kind; while(L>q[i].x) if(++f[s[--L]]==1) ++kind; while(R>q[i].y) if(!--f[s[R--]]) --kind; while(R<q[i].y) if(++f[s[++R]]==1) ++kind; while(T<q[i].last) ++T,Change(r[T].x,r[T].y); while(T>q[i].last) Change(r[T].x,r[T].last),--T; Ans[q[i].time]=kind; } for(int i=1;i<=cnt1;i++) printf("%d ",Ans[i]); return 0; }
分块
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define MK 8 #define MN 11000 char B[1<<23],*S=B; #define getchar() (*S++) using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,s[MN+5],l[MN*2+5],kind[MK+1][MK+1],tot,size,mx,f[MK+1][MK+1][MN+2],pos[MN+5]; struct ques{int kind,x,y;}q[MN+5]; char op; int main() { fread(B,1,1<<23,stdin); tot=n=read();m=read(); register int i,j,k; for(i=1;i<=n;i++) s[i]=l[i]=read(); for(i=1;i<=m;i++) { do op=getchar(); while(op!='Q'&&op!='R');q[i].x=read();q[i].y=read(); if(op=='Q') q[i].kind=2; else q[i].kind=1,l[++tot]=q[i].y; } sort(l+1,l+tot+1);int sz=1; for(i=2;i<=tot;i++) if(l[i]!=l[i-1]) l[++sz]=l[i];tot=sz; for(i=1;i<=n;i++)s[i]=lower_bound(l+1,l+tot+1,s[i])-l; size=(n+MK-1)/MK;mx=(n+size-1)/size; for(i=1;i<=mx;i++) for(j=(i-1)*size+1;j<=n;j++) for(k=(j-1)/size+1;k<=mx;k++) if(++f[i][k][s[j]]==1) ++kind[i][k]; for(i=1;i<=m;i++) { if(q[i].kind==1) { q[i].y=lower_bound(l+1,l+tot+1,q[i].y)-l; int pos=(q[i].x-1)/size+1; for(int j=1;j<=pos;j++) for(int k=pos;k<=mx;k++) { if(!--f[j][k][s[q[i].x]]) kind[j][k]--; if(++f[j][k][q[i].y]==1) kind[j][k]++; } s[q[i].x]=q[i].y; } else { int a=max(1,(q[i].x+size/2)/size),b=max(1,(q[i].y+size/2)/size); int st=(a-1)*size+1,ed=b*size; if(q[i].x>st) { for(j=st;j<q[i].x;j++) if(!--f[a][b][s[j]]) --kind[a][b]; } else for(j=q[i].x;j<st;j++) if(++f[a][b][s[j]]==1) ++kind[a][b]; if(q[i].y<ed) { for(j=q[i].y+1;j<=ed;j++) if(!--f[a][b][s[j]]) --kind[a][b]; } else for(j=q[i].y;j>ed;j--) if(++f[a][b][s[j]]==1) ++kind[a][b]; printf("%d ",kind[a][b]); if(q[i].x>st) { for(j=st;j<q[i].x;j++) if(++f[a][b][s[j]]==1) ++kind[a][b]; } else for(j=q[i].x;j<st;j++) if(!--f[a][b][s[j]]) --kind[a][b]; if(q[i].y<ed) { for(j=q[i].y+1;j<=ed;j++) if(++f[a][b][s[j]]==1) ++kind[a][b]; } else for(j=q[i].y;j>ed;j--) if(!--f[a][b][s[j]]) --kind[a][b]; } } return 0; }