【bzoj 3110】K大数查询(整体二分)

传送门biu~
整体二分。我选择把数据用树状数组维护,树状数组可以支持区间修改区间查询。
你们可能永远不会知道一道题没开long long要调多久QAQ

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
#define int long long
struct data{
    int opt,x,y,c;
}a[50005];
int n,m,tim;
int ans[50005];
int p[50005],tmp[2][50005];
int tree[2][50005],t[2][50005];
inline void add(int opt,int x,int num){
    while(x<=n){
        if(t[opt][x]!=tim)  tree[opt][x]=0;
        t[opt][x]=tim;
        tree[opt][x]+=num;
        x+=lowbit(x);
    }
}
inline void add(int l,int r){
    add(0,l,1);add(0,r+1,-1);
    add(1,l,l);add(1,r+1,-(r+1));
}
inline int search(int opt,int x){
    int re=0;
    while(x){
        if(t[opt][x]!=tim)  tree[opt][x]=0;
        t[opt][x]=tim;
        re+=tree[opt][x];
        x-=lowbit(x);
    }
    return re;
}
inline int search(int x){
    return (x+1)*search(0,x)-search(1,x);
}
void binary_search(int L,int R,int l,int r){
    if(L>R || l>r)  return;
    ++tim;
    int mid=l+r>>1;
    if(l==r){
        for(int i=L;i<=R;++i){
            if(a[p[i]].opt==2)  ans[p[i]]=mid;
        }
        return;
    }
    tmp[0][0]=tmp[1][0]=0;
    for(int i=L;i<=R;++i){
        int x=p[i];
        if(a[x].opt==1){
            if(a[x].c<=mid)     tmp[0][++tmp[0][0]]=x;
            else{
                tmp[1][++tmp[1][0]]=x;
                add(a[x].x,a[x].y);
            }
        }
        else{
            int tot=search(a[x].y)-search(a[x].x-1);
            if(tot<a[x].c){
                a[x].c-=tot;
                tmp[0][++tmp[0][0]]=x;
            }
            else tmp[1][++tmp[1][0]]=x;
        }
    }
    int rL=L+tmp[0][0];
    memcpy(p+L,tmp[0]+1,sizeof(p[0])*tmp[0][0]);
    memcpy(p+rL,tmp[1]+1,sizeof(p[0])*tmp[1][0]);
    binary_search(L,rL-1,l,mid);
    binary_search(rL,R,mid+1,r);
}
#undef int
int main(){
#define int long long
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;++i)   scanf("%lld%lld%lld%lld",&a[i].opt,&a[i].x,&a[i].y,&a[i].c),p[i]=i;
    binary_search(1,m,1,n);
    for(int i=1;i<=m;++i){
        if(a[i].opt==2) printf("%lld\n",ans[i]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zP1nG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值