整体二分题,很好理解,就是将查询区间和查询值区间进行整体二分。
#include<cstdio>
using namespace std;
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
typedef long long ll;
const int maxn=50000+100;
ll bit[maxn][2];
int vis[maxn][2];
int tot;
int n,m;
inline int lowbit(int x){
return x&(-x);
}
inline void update(int x,int ind,int v){
while(x<=n){
if(vis[x][ind]!=tot){
vis[x][ind]=tot;
bit[x][ind]=0;
}
bit[x][ind]+=(ll)v;
x+=lowbit(x);
}
}
inline void Add(int x,int y){
update(x,0,1);
update(y+1,0,-1);
update(x,1,x);
update(y+1,1,-(y+1));
}
inline ll getSum(int x,int ind){
ll sum=0;
while(x>0){
if(vis[x][ind]==tot) sum+=bit[x][ind];
x-=lowbit(x);
}
return sum;
}
inline ll get_Sum(int x,int y){
ll sum=0;
sum=(ll)(y+1)*getSum(y,0)-getSum(y,1)-(ll)x*getSum(x-1,0)+getSum(x-1,1);
return sum;
}
int ans[maxn];
int tmp[maxn][2];
int Id[maxn];
struct Node{
int type;
int x,y;
int c;
}node[maxn];
void Bin(int l,int r,int L,int R){
if(l>r) return ;
int mid=(L+R)>>1;
if(L==R){
for(int i=l;i<=r;i++) if(node[Id[i]].type==2) ans[Id[i]]=mid;
return;
}
tmp[0][0]=tmp[0][1]=0;
tot++;
for(int i=l;i<=r;i++){
int tmpe=Id[i];
if(node[tmpe].type==1){
if(node[tmpe].c<=mid){
tmp[++tmp[0][0]][0]=tmpe;
}
else{
tmp[++tmp[0][1]][1]=tmpe;
Add(node[tmpe].x,node[tmpe].y);
}
}
else{
ll cnt=get_Sum(node[tmpe].x,node[tmpe].y);
if(cnt<node[tmpe].c){
node[tmpe].c-=cnt;
tmp[++tmp[0][0]][0]=tmpe;
}
else{
tmp[++tmp[0][1]][1]=tmpe;
}
}
}
int t1=l+tmp[0][0]-1;
int t2=l;
for(int i=1;i<=tmp[0][0];i++) Id[t2++]=tmp[i][0];
for(int i=1;i<=tmp[0][1];i++) Id[t2++]=tmp[i][1];
Bin(l,t1,L,mid);
Bin(t1+1,r,mid+1,R);
}
int main(){
scanf("%d%d",&n,&m);
int Max=-1e9;
int Min=1e9;
for(int i=1;i<=m;i++){
scanf("%d%d%d%d",&node[i].type,&node[i].x,&node[i].y,&node[i].c);
Id[i]=i;
if(node[i].type==1){
Max=max(Max,node[i].c);
Min=min(Min,node[i].c);
}
}
Bin(1,m,Min,Max);
for(int i=1;i<=m;i++) if(node[i].type==2) printf("%d\n",ans[i]);
}