题目:洛谷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\n",out[i]);
return 0;
}