分析:
整体二分是一种对修改和询问一起进行二分答案的分治方法,本题整体二分模板题。
不过好像树状数组套主席树也能水过去。
代码:
整体二分:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
inline LL read(){
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=50005;
struct Oprt{
int opt,l,r,no;
LL k;
}q[MAXN],q1[MAXN],q2[MAXN];
int n,m,tot,sav[MAXN];
LL sum[MAXN*4],plu[MAXN*4],kk;int ql,qr;
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mid ((l+r)>>1)
void pushdown(int o,int l,int r){
if(plu[o]==0) return;
sum[lc]+=plu[o]*(mid-l+1);
sum[rc]+=plu[o]*(r-mid);
plu[lc]+=plu[o];
plu[rc]+=plu[o];
plu[o]=0;
}
void upd(int o,int l,int r){
if(ql<=l&&r<=qr){
sum[o]+=kk*(r-l+1);
plu[o]+=kk;
return;
}
pushdown(o,l,r);
if(mid>=ql) upd(lc,l,mid);
if(mid<qr) upd(rc,mid+1,r);
sum[o]=sum[lc]+sum[rc];
}
LL query(int o,int l,int r){
if(ql<=l&&r<=qr){
return sum[o];
}
pushdown(o,l,r);
LL ans=0;
if(mid>=ql) ans+=query(lc,l,mid);
if(mid<qr) ans+=query(rc,mid+1,r);
return ans;
}
#undef lc
#undef rc
void solve(int l,int r,int fs,int ls){
if(fs>ls) return;
if(l==r){
for(int i=fs;i<=ls;i++)
if(q[i].opt==2) sav[q[i].no]=l;
return;
}
bool flag=0;
for(int i=fs;i<=ls;i++)
if(q[i].opt==2){
flag=1;break;
}
if(!flag) return;
int t1=0,t2=0;
for(int i=fs;i<=ls;i++){
if(q[i].opt==2){
ql=q[i].l,qr=q[i].r;
LL temp=query(1,1,n);
if(temp>=q[i].k) q1[++t1]=q[i];
else q[i].k-=temp,q2[++t2]=q[i];
}
else{
if(q[i].k<=mid){
ql=q[i].l,qr=q[i].r,kk=1;
upd(1,1,n);
q1[++t1]=q[i];
}
else q2[++t2]=q[i];
}
}
for(int i=1;i<=t1;i++){
if(q1[i].opt==1){
ql=q1[i].l,qr=q1[i].r,kk=-1;
upd(1,1,n);
}
}
for(int i=1;i<=t1;i++) q[fs-1+i]=q1[i];
for(int i=1;i<=t2;i++) q[fs+t1-1+i]=q2[i];
solve(l,mid,fs,fs+t1-1);
solve(mid+1,r,fs+t1,ls);
}
#undef mid
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
q[i].opt=read();
q[i].l=read();
q[i].r=read();
q[i].k=read();
if(q[i].opt==1) q[i].k=n-q[i].k+1;
else q[i].no=++tot;
}
solve(-MAXN,MAXN,1,m);
for(int i=1;i<=tot;i++){
printf("%d\n",n-sav[i]+1);
}
return 0;
}
树套树(树状数组套主席树):
先挖一个坑