整体二分
Posted sun123zxy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了整体二分相关的知识,希望对你有一定的参考价值。
整体二分其实很类似CDQ...区别在于一个是对区间二分,一个是对值进行二分,并以值划分区间
还是结合一道具体的例题把,请直接看模板B:Dynamic Rankings
/*模板A(不带修改):P3834 可持久化线段树 1(主席树)
略过
//整体二分 #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<ctime> #include<cstdlib> #include<queue> using namespace std; const int INF=999999999; int lowbit(int x){return x&(-x);} struct BIT{ int size,tree[500005]; void init(int mysize){ size=mysize;for(int i=0;i<500005;i++) tree[i]=0; } void change(int id,int val){ for(int i=id;i<=size;i+=lowbit(i)) tree[i]+=val; } int getsum(int id){ if(id==0) return 0; int ans=0; for(int i=id;i>=1;i-=lowbit(i)) ans+=tree[i]; return ans; } int ask(int l,int r){return getsum(r)-getsum(l-1);} }bit; struct Query{ int id,type,l,r,val;//type=1:修改;type=2:查询 }q[500005]; int n,qn; int ans[500005],an; Query tmp1[500005],tmp2[500005]; void Divide(int ql,int qr,int l,int r){ if(ql>qr) return; if(l==r){ for(int i=ql;i<=qr;i++) ans[q[i].id]=l; return; } int mid=(l+r)/2; int t1=0,t2=0; for(int i=ql;i<=qr;i++){ if(q[i].type==1){ if(q[i].val<=mid){ bit.change(q[i].l,1); tmp1[++t1]=q[i]; }else tmp2[++t2]=q[i]; }else if(q[i].type==2){ int d=bit.ask(q[i].l,q[i].r); if(d>=q[i].val) tmp1[++t1]=q[i]; else q[i].val-=d,tmp2[++t2]=q[i]; } } for(int i=1;i<=t1;i++) if(tmp1[i].type==1) bit.change(tmp1[i].l,-1); for(int i=1;i<=t1;i++) q[ql+i-1]=tmp1[i]; for(int i=1;i<=t2;i++) q[ql+t1+i-1]=tmp2[i]; Divide(ql,ql+t1-1,l,mid); Divide(ql+t1,qr,mid+1,r); } int main(){ cin>>n>>an;qn=0; for(int i=1;i<=n;i++){ int x;scanf("%d",&x); q[++qn]=(Query){0,1,i,0,x}; } for(int i=1;i<=an;i++){ int l,r,val; scanf("%d%d%d",&l,&r,&val); q[++qn]=(Query){i,2,l,r,val}; } for(int i=0;i<500005;i++) ans[i]=0; bit.init(500000); Divide(1,qn,0,INF); for(int i=1;i<=an;i++) printf("%d ",ans[i]); return 0; }
*/
模板B(带修改):洛谷P2617 Dynamic Rankings
一句话题意:求带修改区间的区间第k大
动态的解法是主席树套树状数组,然而这玩意不好打呀...
于是从离线的角度思考。
//整体二分 #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<ctime> #include<cstdlib> #include<queue> using namespace std; const int INF=999999999; int lowbit(int x){return x&(-x);} struct BIT{ int size,tree[1000005]; void init(int mysize){ size=mysize;for(int i=0;i<1000005;i++) tree[i]=0; } void change(int id,int val){ for(int i=id;i<=size;i+=lowbit(i)) tree[i]+=val; } int getsum(int id){ if(id==0) return 0; int ans=0; for(int i=id;i>=1;i-=lowbit(i)) ans+=tree[i]; return ans; } int ask(int l,int r){return getsum(r)-getsum(l-1);} }bit; struct Query{ int id,type,l,r,val,dt;//type=1:修改;type=2:查询 }q[1000005]; int n,qn; int ans[1000005],an; Query tmp1[1000005],tmp2[1000005]; void Divide(int ql,int qr,int l,int r){ if(ql>qr) return; if(l==r){ for(int i=ql;i<=qr;i++) if(q[i].type==2) ans[q[i].id]=l; return; } int mid=(l+r)/2; int t1=0,t2=0; for(int i=ql;i<=qr;i++){ if(q[i].type==1){ if(q[i].val<=mid){ bit.change(q[i].l,q[i].dt); tmp1[++t1]=q[i]; }else tmp2[++t2]=q[i]; }else if(q[i].type==2){ int d=bit.ask(q[i].l,q[i].r); if(d>=q[i].val) tmp1[++t1]=q[i]; else q[i].val-=d,tmp2[++t2]=q[i]; } } for(int i=1;i<=t1;i++) if(tmp1[i].type==1) bit.change(tmp1[i].l,-tmp1[i].dt); for(int i=1;i<=t1;i++) q[ql+i-1]=tmp1[i]; for(int i=1;i<=t2;i++) q[ql+t1+i-1]=tmp2[i]; Divide(ql,ql+t1-1,l,mid); Divide(ql+t1,qr,mid+1,r); } int arr[1000005]; int main(){ int cirno; cin>>n>>cirno;qn=0,an=0; for(int i=1;i<=n;i++){ int x;scanf("%d",&x); q[++qn]=(Query){0,1,i,0,x,1}; arr[i]=x; } for(int i=1;i<=cirno;i++){ char type[5]; scanf("%s",type); int l,r,val; if(type[0]==‘C‘){ scanf("%d%d",&l,&val); q[++qn]=(Query){0,1,l,0,arr[l],-1}; arr[l]=val; q[++qn]=(Query){0,1,l,0,val,1}; }else if(type[0]==‘Q‘){ scanf("%d%d%d",&l,&r,&val); q[++qn]=(Query){++an,2,l,r,val,0}; } } for(int i=0;i<1000005;i++) ans[i]=0; bit.init(1000000); Divide(1,qn,0,INF); for(int i=1;i<=an;i++) printf("%d ",ans[i]); return 0; }
以上是关于整体二分的主要内容,如果未能解决你的问题,请参考以下文章