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

时间:2023-03-08 16:42:35
BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint


之前用树套树抄过一次...然而我并不适合写那玩意儿...

加上时间序的整体二分

普通的整体二分先处理了所有$[l,mid]$的影响因子在计算询问的答案来分组

这里要按时间序来处理影响因子和询问

可以把时间放在第一维,反正二分的时候要按权值(答案)分成两部分

然后需要区间加和区间求和,可以用树状数组

数据太坑了还要$unsigned int$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=5e5+;
typedef long long ll;
typedef unsigned int uint;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
} int n,m;
int CL;
struct BIT{
uint c[N],mark[N];
inline int lowbit(int x){return x&-x;}
inline void add(int p,int v){
for(;p<=n;p+=lowbit(p)){
if(mark[p]==CL) c[p]+=v;
else mark[p]=CL,c[p]=v;
}
}
inline uint sum(int p){
uint re=;
for(;p;p-=lowbit(p))
if(mark[p]==CL) re+=c[p];
return re;
}
inline uint que(int l,int r){
return sum(r)-sum(l-);
}
}c1,c2;
inline void add(int l,int r){
c1.add(l,);c1.add(r+,-);
c2.add(l,l);c2.add(r+,-(r+));
}
inline uint que(int l,int r){
return (r-l+)*c1.que(,l)+(r+)*c1.que(l+,r)-c2.que(l+,r);
}
struct Operation{
int op,l,r,k;
}a[N];
int id[N],t1[N],t2[N];
uint cur[N],ans[N];
void Sol(int l,int r,int ql,int qr){//printf("Sol %d %d %d %d\n",l,r,ql,qr);
if(ql>qr) return;
if(l==r){
for(int i=ql;i<=qr;i++)
if(a[id[i]].op==) ans[id[i]]=l;
return;
}
int mid=(l+r)>>,p1=,p2=;
CL++;
for(int i=ql;i<=qr;i++){
int _=i;i=id[i];
if(a[i].op==){
if(a[i].k<=mid) t1[++p1]=i;
else add(a[i].l,a[i].r),t2[++p2]=i;
}else{
uint s=cur[i]+que(a[i].l,a[i].r);
if(s<a[i].k) cur[i]=s,t1[++p1]=i;
else t2[++p2]=i;
}
i=_;
}
for(int i=;i<=p1;i++) id[ql+i-]=t1[i];
for(int i=;i<=p2;i++) id[ql+p1+i-]=t2[i];
Sol(l,mid,ql,ql+p1-);Sol(mid+,r,ql+p1,qr);
}
int main(){
freopen("in","r",stdin);
n=read();m=read();
for(int i=;i<=m;i++){
a[i].op=read(),a[i].l=read(),a[i].r=read(),a[i].k=read();
id[i]=i;
}
Sol(,n,,m);
for(int i=;i<=m;i++) if(a[i].op==) printf("%d\n",ans[i]);
}