题目:洛谷P1903、BZOJ2120。
题目大意:
给你一列数,有两种操作:
1. 询问区间$[L, R]$内不同数出现的个数。
2. 单点修改。
解题思路:
带修莫队。
仍然运用分块思路,加了一个修改时间而已。
所以以$L$所在的块为第一关键字,$R$所在的块为第二关键字,修改时间为第三关键字排序即可。
C++ Code:
#include<bits/stdc++.h> int n,m,sz,a[10005],cnt[1000005],k=0,T=0,b[10005],ans,out[10005]; char c[3]; #define be(i) (i/sz) inline int readint(){ int c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } struct query{ int l,r,t,num; bool operator <(const query& rhs)const{ if(be(l)!=be(rhs.l))return l<rhs.l; if(be(r)!=be(rhs.r))return r<rhs.r; return t<rhs.t; } }q[10005]; struct Time{ int pos,now,old; }tim[10005]; inline void change(int d,int c){ cnt[d]+=c; if(c==-1&&!cnt[d])--ans;else if(c==1&&cnt[d]==1)++ans; } int main(){ n=readint(),m=readint(); sz=(int)pow(n,2.0/3); for(int i=1;i<=n;++i)a[i]=b[i]=readint(); for(int i=1;i<=m;++i){ scanf("%s",c); if(c[0]=='Q'){ q[++k].l=readint(); q[k].r=readint(); q[k].t=T; q[k].num=k; }else{ tim[++T].pos=readint(); tim[T].now=readint(); tim[T].old=b[tim[T].pos]; b[tim[T].pos]=tim[T].now; } } std::sort(q+1,q+k+1); memset(cnt,0,sizeof cnt); int l=1,r=1,t=0; ans=1; ++cnt[a[1]]; for(int i=1;i<=k;++i){ while(t<q[i].t){ ++t; if(l<=tim[t].pos&&tim[t].pos<=r) change(a[tim[t].pos],-1),change(tim[t].now,1); a[tim[t].pos]=tim[t].now; } while(q[i].t<t){ if(l<=tim[t].pos&&tim[t].pos<=r) change(a[tim[t].pos],-1),change(tim[t].old,1); a[tim[t].pos]=tim[t].old; --t; } while(r<q[i].r)change(a[++r],1); while(q[i].r<r)change(a[r--],-1); while(q[i].l<l)change(a[--l],1); while(l<q[i].l)change(a[l++],-1); out[q[i].num]=ans; } for(int i=1;i<=k;++i)printf("%d ",out[i]); return 0; }