[ZJOI2013]K大数查询
整体二分?
二分答案c,求:
solve(optl,optr,ansl,ansr);
即work出操作在[ol,or],答案在[al,ar]?
先搞出一个答案mid,再把opt扫一边。
如果是1
如果c>mid,就丢进树状数组里面。
区间+1?
三个树状数组的事情。
然后把操作扔进右边QwQ
如果c<=mid 就不管它
然后把操作丢进左边。
如果是2
查询一下和。
如果sum<k
则意味着前面的操作里凑不出k个比mid大的数。
则第k大一定比mid小。
丢进左边。
否则 丢进右边。
然后
solve(optl,sizel,ansl,mid);
solve(sizel+1,optr,mid+1,ansr);
直到l==r为止。
上代码:
//MADE BY BOBOYANG
#include <bits/stdc++.h>
#define LL long long int
#define dob double
using namespace std;
const int N = 50010;
struct Data{
int type,l,r,c,id;
bool operator <(const Data &a)const{
return id<a.id;
}
}opt[N],que1[N],que2[N];
int n,m,tim;LL Ans[N];
struct BIT{
LL A1[N],A2[N],A3[N];
int vis1[N],vis2[N],vis3[N];
inline int lb(int k){
return k&-k;
}
inline void update(LL *A,int *vis,int x,int val){
for(;x<=n;x+=lb(x)){
if(vis[x]!=tim)A[x]=0;
A[x]+=val;vis[x]=tim;
}
}
inline LL query(LL *A,int *vis,int x,LL ans=0){
for(;x;x-=lb(x)){
if(vis[x]!=tim)A[x]=0;
ans+=A[x];vis[x]=tim;
}
return ans;
}
inline void add(int l,int r,int dt){
update(A2,vis2,l,dt);update(A2,vis2,r+1,-dt);
update(A3,vis3,l,dt*l);update(A3,vis3,r+1,-dt*(r+1));
}
inline LL sum(int l,int r){
LL sl=A1[l-1]+l*query(A2,vis2,l-1)-query(A3,vis3,l-1);
LL sr=A1[r]+(r+1)*query(A2,vis2,r)-query(A3,vis3,r);
return sr-sl;
}
}T;
inline int gi(){
int x=0,res=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*res;
}
inline void solve(int optl,int optr,int l,int r){
if(optl>optr)return;++tim;
if(l==r){
for(int i=optl;i<=optr;++i)
if(opt[i].type==2)
Ans[opt[i].id]=l;
return;
}
int mid=((l+r+2*n)>>1)-n,tot1=0,tot2=0;
for(int i=optl;i<=optr;++i){
if(opt[i].type==1){
if(opt[i].c>mid){
T.add(opt[i].l,opt[i].r,1);
que2[++tot2]=opt[i];
}
else que1[++tot1]=opt[i];
}
else{
LL sum=T.sum(opt[i].l,opt[i].r);
if(sum<opt[i].c){
opt[i].c-=sum;
que1[++tot1]=opt[i];
}
else que2[++tot2]=opt[i];
}
}
int k=optl;
for(int i=1;i<=tot1;++i)opt[k++]=que1[i];
for(int i=1;i<=tot2;++i)opt[k++]=que2[i];
solve(optl,optl+tot1-1,l,mid);
solve(optr-tot2+1,optr,mid+1,r);
}
int main()
{
n=gi();m=gi();
for(int i=1;i<=m;++i){
opt[i].type=gi();
opt[i].l=gi();opt[i].r=gi();
opt[i].c=gi();opt[i].id=i;
}
solve(1,m,-n,n);
sort(opt+1,opt+m+1);
for(int i=1;i<=m;++i)
if(opt[i].type==2)
printf("%lld\n",Ans[i]);
return 0;
}