bzoj3110 K大数查询

题目:有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c

如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

N<=50000

M<=50000

思路:二分答案,要用到树状数组区间更新

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
//0x3f3f3f3f

const int maxn=5e4+50;
struct Node{
    int type,id,a,b;
    LL c;
}q[maxn],q1[maxn],q2[maxn];
struct BIT{
    int n;
    LL bit0[maxn],bit1[maxn];
    void init(int _n){
        n=_n;
        mm(bit0,0);
        mm(bit1,0);
    }
    void add(LL *b,int i,LL val){
        for(;i<=n;i+=i&(-i))
            b[i]+=val;
    }
    LL sum(LL *b,int i){
        LL ret=0;
        for(;i>0;i-=i&(-i))
            ret+=b[i];
        return ret;
    }
    void ADD(int l,int r,LL c){
        add(bit0,l,-c*(l-1));
        add(bit0,r+1,c*r);
        add(bit1,l,c);
        add(bit1,r+1,-c);
    }
    LL SUM(int l,int r){
        LL ret=sum(bit0,r)-sum(bit0,l-1);
        ret+=sum(bit1,r)*r-sum(bit1,l-1)*(l-1);
        return ret;
    }
}bit;
int ans[maxn],vis[maxn];
int n,m;
void cdq(int L,int R,int l,int r){
    if(L>R) return;
    if(l==r){
        for(int i=L;i<=R;i++)
            if(q[i].type==2)
                ans[q[i].id]=l;
        return;
    }
    int sz1=0,sz2=0,mid=(l+r)>>1;
    for(int i=L;i<=R;i++){
        if(q[i].type==1){
            if(q[i].c<=mid) q1[sz1++]=q[i];
            else{
                bit.ADD(q[i].a,q[i].b,1);
                q2[sz2++]=q[i];
            }
        }
        else{
            LL ret=bit.SUM(q[i].a,q[i].b);
            if(ret>=q[i].c){
                q2[sz2++]=q[i];
            }
            else{
                q[i].c-=ret;
                q1[sz1++]=q[i];
            }
        }
    }
    for(int i=0;i<sz2;i++)
        if(q2[i].type==1)
            bit.ADD(q2[i].a,q2[i].b,-1);
    memcpy(q+L,q1,sz1*sizeof(Node));
    memcpy(q+L+sz1,q2,sz2*sizeof(Node));
    cdq(L,L+sz1-1,l,mid);
    cdq(L+sz1,R,mid+1,r);
}
int main(){

//    freopen("D:\\input.txt","r",stdin);
//    freopen("D:\\output.txt","w",stdout);
    while(~scanf("%d%d",&n,&m)){
        bit.init(n);
        mm(vis,0);
        mm(ans,0);
        int mi=n,mx=-n;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%lld",&q[i].type,&q[i].a,&q[i].b,&q[i].c);
            q[i].id=i;
            if(q[i].type==2)
                vis[i]=1;
            else{
                mi=min(mi,(int)q[i].c);
                mx=max(mx,(int)q[i].c);
            }
        }
        cdq(1,m,mi,mx);
        for(int i=1;i<=m;i++)
            if(vis[i])
                printf("%d\n",ans[i]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值