首页 > 代码库 > BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]

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]);}

 

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