【传送门:BZOJ2120】
简要题意:
有n个数,有m种操作:
1.Q l r求出l到r中共有多少种不同的数
2.R x c将第x个数改为c
题解:
带修莫队例题
具体请膜大米饼
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int l,r,t,ans; int id; }a[11000];int lenx; struct ch { int x,c,last; }b[11000];int leny; int block; int n,m,ans; char s[10]; int col[11000],pos[11000]; int last[11000]; bool cmpx(node n1,node n2) { if(pos[n1.l]>pos[n2.l])return false; else if(pos[n1.l]<pos[n2.l])return true; else if(pos[n1.r]>pos[n2.r])return false; else if(pos[n1.r]<pos[n2.r])return true; else return n1.t<n2.t; } int sum[1100000]; void change2(int x,int c) { int tmp=sum[col[x]]; sum[col[x]]+=c; if(tmp==0&&sum[col[x]]==1)ans++; else if(tmp==1&&sum[col[x]]==0)ans--; } int l,r,t; void change1(int x,int c) { if(l<=x&&x<=r) { sum[col[x]]--;if(sum[col[x]]==0)ans--; col[x]=c; sum[col[x]]++;if(sum[col[x]]==1)ans++; } else col[x]=c; } bool cmpy(node n1,node n2) { return n1.id<n2.id; } int main() { lenx=leny=0; scanf("%d%d",&n,&m); block=sqrt(n); memset(last,0,sizeof(last)); for(int i=1;i<=n;i++){scanf("%d",&col[i]);last[i]=col[i];} for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1; for(int i=1;i<=m;i++) { scanf("%s",s+1); if(s[1]=='Q') { int x,y; scanf("%d%d",&x,&y); a[++lenx].l=x;a[lenx].r=y;a[lenx].t=leny; a[lenx].id=i; } else { int x,y; scanf("%d%d",&x,&y); b[++leny].x=x;b[leny].c=y; b[leny].last=last[x]; last[x]=y; } } sort(a+1,a+1+lenx,cmpx); l=1,r=0,t=0;ans=0; for(int i=1;i<=lenx;i++) { while(t>a[i].t) change1(b[t].x,b[t].last),t--; while(t<a[i].t) t++,change1(b[t].x,b[t].c); while(r<a[i].r) r++,change2(r,1); while(l>a[i].l) l--,change2(l,1); while(r>a[i].r) change2(r,-1),r--; while(l<a[i].l) change2(l,-1),l++; a[i].ans=ans; } sort(a+1,a+1+lenx,cmpy); for(int i=1;i<=lenx;i++)printf("%d ",a[i].ans); return 0; }