[国家集训队]数颜色 / 维护队列(带修莫队)
题意:
对给定的序列,回答m个询问,Q:询问l到r中不同的颜色数量,R:将下标为x的颜色改为y
题解:
带修莫队,相对普通的莫队,加多了一个关键字排序
#include<bits/stdc++.h> #define num ch-'0' #define pn putchar('\n') using namespace std; template<typename T> void read(T &res) { bool flag=false;char ch; while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true); for(res=num;isdigit(ch=getchar());res=res*10+num); flag&&(res=-res); } template<typename T> void write(T x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } const int maxn=50010; const int M=50010; int n,m; int qu_num,op_num; int lst[maxn],col[maxn],blo[maxn],cnt[1000010],res[M]; struct query{ int l,r,t,pos; bool operator <(const query &a) const { return blo[a.l]==blo[l]?(blo[a.r]==blo[r]?t<a.t:blo[r]<blo[a.r]):blo[l]<blo[a.l]; } }qu[M]; struct oper { int x,lst,now; }op[M]; int main() { read(n),read(m); int q=pow(n,0.666666); for(int i=1;i<=n;i++) read(col[i]),blo[i]=(i-1)/q+1,lst[i]=col[i]; int x,y; for(int i=1;i<=m;i++) { char ch[5]; scanf("%s",ch); scanf("%d%d",&x,&y); if(ch[0]=='Q') qu[++qu_num].l=x,qu[qu_num].r=y,qu[qu[qu_num].pos=qu_num].t=op_num; else op[++op_num].x=x,op[op_num].lst=lst[x],op[op_num].now=y,lst[x]=y; } sort(qu+1,qu+1+qu_num); int l=0,r=0,t=0,ans=0; for(int i=1;i<=qu_num;i++) { while(t<qu[i].t) { t++; ///最初的t=0,先增 if(l<=op[t].x&&op[t].x<=r) { if(!--cnt[col[op[t].x]]) ans--; if(!cnt[op[t].now]++) ans++; } col[op[t].x]=op[t].now; } while(t>qu[i].t) { if(l<=op[t].x&&op[t].x<=r) { if(!--cnt[col[op[t].x]]) ans--; if(!cnt[op[t].lst]++) ans++; } col[op[t].x]=op[t].lst; t--; } while(r<qu[i].r) if(!cnt[col[++r]]++) ans++; while(l>qu[i].l) if(!cnt[col[--l]]++) ans++; while(r>qu[i].r) if(!--cnt[col[r--]]) ans--; while(l<qu[i].l) if(!--cnt[col[l++]]) ans--; res[qu[i].pos]=ans; } for(int i=1;i<=qu_num;i++) write(res[i]),pn; return 0; }
所谓人生,一半惊喜,一半遗憾