这东西是个应用为O(logn)的莫队。
正常莫队的updata函数转移是O(1)的,可这个题时间非常宽泛,可以套两个树状数组,那两个东西很好维护,第一个直接普通权值树状数组维护,第二个开一个桶,记录当前区间内某个数的出现次数,当从0->1时,第二个树状数组+权,1->0时,第二个树状数组-权,别的情况不用管,这样就可以用莫队轻松搞掉了。
#include<bits/stdc++.h> #define lowbit(x) (x&(-x)) using namespace std; int read(){ int sum=0,f=1;char x=getchar(); while(x<'0'||x>'9'){ if(x=='-') f=-1; x=getchar(); }while(x>='0'&&x<='9'){ sum=sum*10+x-'0'; x=getchar(); }return sum*f; } struct MoCap{ int l,r,id,a,b; }q[1000500]; int n,m,part,L,R,ans1[1000500],ans2[1000500]; int bl[100500],col[100500],t1[100500],t2[100500],cnt[100500]; bool cmp(MoCap a,MoCap b){ return bl[a.l]==bl[b.l]?a.r<b.r:a.l<b.l; } void add1(int pos,int val){ for(int i=pos;i<=n;i+=lowbit(i)) t1[i]+=val; } int ask1(int pos){ int ans=0; for(int i=pos;i>=1;i-=lowbit(i)) ans+=t1[i]; return ans; } void add2(int pos,int val){ for(int i=pos;i<=n;i+=lowbit(i)) t2[i]+=val; } int ask2(int pos){ int ans=0; for(int i=pos;i>=1;i-=lowbit(i)) ans+=t2[i]; return ans; } void updata(int i,int val){ if(cnt[col[i]]==1&&val==-1){ add2(col[i],val); } if(cnt[col[i]]==0&&val==1){ add2(col[i],val); } add1(col[i],val); cnt[col[i]]+=val; // qaq1=ask1(R)-ask1(L-1); // qaq2=ask2(R)-ask2(L-1); } int main(){ n=read();m=read();part=sqrt(n); for(int i=1;i<=n;i++){ col[i]=read(); bl[i]=i/part+1; } for(int i=1;i<=m;i++){ q[i].l=read(); q[i].r=read(); q[i].a=read(); q[i].b=read(); q[i].id=i; }sort(q+1,q+1+m,cmp); int l=1,r=0; for(int i=1;i<=m;i++){ L=q[i].a;R=q[i].b; while(l<q[i].l) updata(l++,-1); while(l>q[i].l) updata(--l,+1); while(r<q[i].r) updata(++r,+1); while(r>q[i].r) updata(r--,-1); ans1[q[i].id]=ask1(R)-ask1(L-1); ans2[q[i].id]=ask2(R)-ask2(L-1); } for(int i=1;i<=m;i++) printf("%d %d ",ans1[i],ans2[i]); return 0; }