整体二分

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;
}
View Code

*/

模板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;
}
View Code

 

以上是关于整体二分的主要内容,如果未能解决你的问题,请参考以下文章

整体二分

整体二分QAQ

POJ2104 K-th Number(整体二分)

整体二分初步

静态区间第k小 - 整体二分

bzoj 3110 [Zjoi2013]K大数查询 整体二分