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