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+5;
typedef long long ll;
typedef unsigned int uint;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; 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=0;
        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-1);
    }
}c1,c2;
inline void add(int l,int r){
    c1.add(l,1);c1.add(r+1,-1);
    c2.add(l,l);c2.add(r+1,-(r+1));
}
inline uint que(int l,int r){
    return (r-l+1)*c1.que(1,l)+(r+1)*c1.que(l+1,r)-c2.que(l+1,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==2) ans[id[i]]=l;
        return;
    }
    int mid=(l+r)>>1,p1=0,p2=0;
    CL++;
    for(int i=ql;i<=qr;i++){
        int _=i;i=id[i];
        if(a[i].op==1){
            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=1;i<=p1;i++) id[ql+i-1]=t1[i];
    for(int i=1;i<=p2;i++) id[ql+p1+i-1]=t2[i];
    Sol(l,mid,ql,ql+p1-1);Sol(mid+1,r,ql+p1,qr);
}
int main(){
    freopen("in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=m;i++){
        a[i].op=read(),a[i].l=read(),a[i].r=read(),a[i].k=read();
        id[i]=i;
    }
    Sol(1,n,1,m);
    for(int i=1;i<=m;i++) if(a[i].op==2) printf("%d\n",ans[i]);
}

 

posted @ 2017-02-26 23:16  Candy?  阅读(566)  评论(0编辑  收藏  举报