BZOJ3236: [Ahoi2013]作业 树状数组维护 莫队
Posted TS_Hugh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3236: [Ahoi2013]作业 树状数组维护 莫队相关的知识,希望对你有一定的参考价值。
水果~~~~
关于四个while可行性的证明:区间有正确性所以不管那团小东西用没有duang~反它最终总会由于两次覆盖二准确
关于区间种数可行性的证明:他会在0 1间(或两边)来回跳动(过程中),最终会停在一个大于等于0的地方由于多次覆盖,最终也会趋于准确
#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<algorithm> #define M 1000005 #define N 100005 using namespace std; int zero[N],a[N],b[N],pos[N],len,l,r,had[N],n,m; struct Q { int l,r,ans1,ans2,z,y,id; }q[M]; int comp(const Q x,const Q y) { return pos[x.l]<pos[y.l]||(pos[x.l]==pos[y.l]&&x.r<y.r); } int end_comp(const Q x,const Q y) { return x.id<y.id; } inline void update_a(int x,int i) { while(x<=n) { a[x]+=i; x+=x&(-x); } } inline void update_b(int x,int i) { while(x<=n) { b[x]+=i; x+=x&(-x); } } inline int sum_a(int x) { int ret=0; while(x>0) { ret+=a[x]; x-=x&(-x); } return ret; } inline int sum_b(int x) { int ret=0; while(x>0) { ret+=b[x]; x-=x&(-x); } return ret; } void pre() { scanf("%d%d",&n,&m); len=(int)(sqrt(n+0.5)); for(int i=1;i<=n;i++) { scanf("%d",&zero[i]); pos[i]=(i-1)/len+1; } l=r=1; update_a(zero[1],1); update_b(zero[1],1); had[zero[1]]=1; for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].z,&q[i].y); q[i].id=i; } sort(q+1,q+m+1,comp); } inline void via(int pl,int i) { if(i==1) { update_a(zero[pl],1); had[zero[pl]]++; if(had[zero[pl]]==1) update_b(zero[pl],1); } else { update_a(zero[pl],-1); had[zero[pl]]--; if(had[zero[pl]]==0) update_b(zero[pl],-1); } } void work() { for(int i=1;i<=m;i++) { while(l<q[i].l)via(l++,-1); while(l>q[i].l)via(--l,1); while(r<q[i].r)via(++r,1); while(r>q[i].r)via(r--,-1); q[i].ans1=sum_a(q[i].y)-sum_a(q[i].z-1); q[i].ans2=sum_b(q[i].y)-sum_b(q[i].z-1); } } void print() { sort(q+1,q+m+1,end_comp); for(int i=1;i<=m;i++) printf("%d %d\n",q[i].ans1,q[i].ans2); } int main() { //freopen("ahoi2013_homework.in","r",stdin); //freopen("ahoi2013_homework.out","w",stdout); pre(); work(); print(); return 0; }
以上是关于BZOJ3236: [Ahoi2013]作业 树状数组维护 莫队的主要内容,如果未能解决你的问题,请参考以下文章