思路:
带修改的莫队;
对于离线排序询问的算法,如何修改呢?
每个询问添加一个修改标记;
表示当前询问在第几个修改之后;
然后把修改标记作为第三关键字来排序;
每次更新端点,先更新时间;
块的大小为n的2/3次方;
来,上代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 100050 struct QueryType { int l,r,t,id; }; struct QueryType qu[maxn]; struct ChangeType { int to,x,h; }; struct ChangeType cha[maxn]; int n,m,size=440,tot,num,ai[maxn],bel[maxn],ti[maxn*10],ans[maxn]; int now; bool if_[maxn]; inline void in(int &now) { char Cget=getchar();now=0; while(Cget>'9'||Cget<'0') Cget=getchar(); while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } } bool cmp(QueryType aa,QueryType bb) { if(bel[aa.l]==bel[bb.l]) { if(bel[aa.r]==bel[bb.r]) return aa.t<bb.t; else return aa.r<bb.r; } else return aa.l<bb.l; } inline void change(int x) { if(if_[cha[x].to]) { ti[ai[cha[x].to]]--; if(!ti[ai[cha[x].to]]) now--; } cha[x].h=ai[cha[x].to]; ai[cha[x].to]=cha[x].x; if(if_[cha[x].to]) { if(!ti[ai[cha[x].to]]) now++; ti[ai[cha[x].to]]++; } } inline void unchange(int x) { if(if_[cha[x].to]) { ti[ai[cha[x].to]]--; if(!ti[ai[cha[x].to]]) now--; } ai[cha[x].to]=cha[x].h; if(if_[cha[x].to]) { if(!ti[ai[cha[x].to]]) now++; ti[ai[cha[x].to]]++; } } inline void updata(int to,int x) { int pos=ti[ai[to]]; ti[ai[to]]+=x; if(ti[ai[to]]==0&&pos==1) now--; if(ti[ai[to]]==1&&pos==0) now++; if(x==1) if_[to]=true; else if_[to]=false; } int main() { in(n),in(m);char ch[4];int l,r,t; for(int i=1;i<=n;i++) in(ai[i]),bel[i]=(i-1)/size; for(int i=1;i<=m;i++) { scanf("%s",ch);in(l),in(r); if(ch[0]=='Q') qu[++tot].l=l,qu[tot].r=r,qu[tot].t=num,qu[tot].id=tot; else cha[++num].to=l,cha[num].x=r; } sort(qu+1,qu+tot+1,cmp),l=1,r=0,t=0,now=0; for(int no=1;no<=tot;no++) { while(t<qu[no].t) change(++t); while(t>qu[no].t) unchange(t--); while(r<qu[no].r) updata(++r,1); while(r>qu[no].r) updata(r--,-1); while(l<qu[no].l) updata(l++,-1); while(l>qu[no].l) updata(--l,1); ans[qu[no].id]=now; } for(int i=1;i<=tot;i++) printf("%d ",ans[i]); fclose(stdin),fclose(stdout); return 0; }