整体二分学习笔记!

最近学习效率挺高的嘻嘻,学了好几个板子,所以最近大概会发好几篇学习笔记,打算先尽快把知识点学完再一个个落实(我学习笔记里放的题目都还麻油做的呢QAQ,,,

然后就直接进入正题,港下整体二分

经常能看到整体二分和cdq分治出现在一个学习笔记中,因为这两个是比较常见的离线算法,又都是分治,只是因为我是比较久之前就学了cdq分治辣,,,所以就麻油放在一块儿辣

从上面就可以看出,整体二分是一种离线算法

然后具体来说,如果碰到一下三个特征时就可以往整体二分方面想辣:

1)有多组询问且麻油强制在线

2)单个询问可以二分查找,且如果只有单个询问时check的复杂度是过得去的

3)所有询问的操作都是一样的

然后如果现在已经想到是整体二分了,一般是怎么做的呢

solve(op_l,op_r,as_l,as_r):op表示操作号,as表示当前二分的答案(就是while里面的l和r

然后取as_mid,计算[op_l,op_r]中的操作:

答案是在as_mid的左边的(也就是小于的),存入l_op[]数组

答案是在as_mid的右边的(也就是大于的),存入r_op[]数组

然后分开处理,solve(op_l,op_l+cnt_l-1,as_l,as_mid);solve(op_l+cnt_l,op_r,as_mid+1,as_r);

然后当as_l==as_r的时候就和单次check是一样的,说明[op_l,op_r]的操作ans出来辣,就是as_l

然后整体二分通常是用来解决待修改区间第k大类问题的

先放个例题链接放个代码,具体晚自习解释w(如果咕了请提醒我QAQ,,,

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define rg register
#define gc getchar()
#define ll long long
#define ls(x) (x<<1)
#define rs(x) (x<<1)|1
#define rp(i,x,y) for(rg ll i=x;i<=y;++i)

const ll M=50000+10;
ll n,m,cnt_as,as[M];
struct ques{ll opt,a,b,c,id;}op[M],l_op[M],r_op[M];
struct tree{bool isclr;ll ad,dat;il void clr(){isclr=ad=dat=0;}}tr[M<<3];

il ll rd()
{
    rg char ch=gc;rg ll x=0;rg bool y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void clrtr(ll x){if(tr[x].isclr){tr[ls(x)].clr();tr[rs(x)].clr();tr[ls(x)].isclr=1;tr[rs(x)].isclr=1;tr[x].isclr=0;}}
il void push_lazy(ll x,ll len,ll dat){tr[x].dat+=dat*len;tr[x].ad+=dat;}
il void pushdown(ll x,ll l,ll r){ll mid=(l+r)>>1;clrtr(x);push_lazy(ls(x),mid-l+1,tr[x].ad);push_lazy(rs(x),r-mid,tr[x].ad);tr[x].ad=0;}
il void modify(ll nw,ll nw_l,ll nw_r,ll to_l,ll to_r)
{
    pushdown(nw,nw_l,nw_r);
    if(nw_l>=to_l && nw_r<=to_r)return void(push_lazy(nw,nw_r-nw_l+1,1));
    tr[nw].dat+=to_r-to_l+1;ll mid=(nw_l+nw_r)>>1;
    if(to_r<=mid)return void(modify(ls(nw),nw_l,mid,to_l,to_r));if(to_l>mid)return void(modify(rs(nw),mid+1,nw_r,to_l,to_r));
    modify(ls(nw),nw_l,mid,to_l,mid);modify(rs(nw),mid+1,nw_r,mid+1,to_r);    
}
il ll query(ll nw,ll nw_l,ll nw_r,ll to_l,ll to_r)
{
    pushdown(nw,nw_l,nw_r);
    if(to_l<=nw_l && nw_r<=to_r)return tr[nw].dat;
    ll mid=(nw_l+nw_r)>>1,as=0;
    if(to_l<=mid)as+=query(ls(nw),nw_l,mid,to_l,to_r);if(to_r>mid)as+=query(rs(nw),mid+1,nw_r,to_l,to_r);
    return as;
}
il void solv(ll op_l,ll op_r,ll as_l,ll as_r)
{
    if(op_l>op_r)return;if(as_l==as_r){rp(i,op_l,op_r)as[op[i].id]=as_l;return;}
    ll mid=(as_l+as_r)>>1,l_cnt=0,r_cnt=0;
    rp(i,op_l,op_r)
    {
        if(op[i].opt==1)if(op[i].c<=mid)l_op[++l_cnt]=op[i];else modify(1,1,n,op[i].a,op[i].b),r_op[++r_cnt]=op[i];
        else{ll tmp=query(1,1,n,op[i].a,op[i].b);if(tmp>=op[i].c)r_op[++r_cnt]=op[i];else op[i].c-=tmp,l_op[++l_cnt]=op[i];}
    }
    rp(i,1,l_cnt)op[op_l+i-1]=l_op[i];rp(i,1,r_cnt)op[op_l+l_cnt+i-1]=r_op[i];
    tr[1].clr();tr[1].isclr=1;solv(op_l,op_l+l_cnt-1,as_l,mid);solv(op_l+l_cnt,op_r,mid+1,as_r);
}

int main()
{
    n=rd();m=rd();rp(i,1,m){op[i].opt=rd(),op[i].a=rd(),op[i].b=rd(),op[i].c=rd();if(op[i].opt==2)op[i].id=++cnt_as;}
    solv(1,m,-n,n);
    rp(i,1,cnt_as)printf("%lld\n",as[i]);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/lqsukida/p/10375827.html
0条评论
添加一条新回复