[BZOJ3110][Zjoi2013]K大数查询:整体二分/树套树(树状数组套主席树)

分析:

整体二分是一种对修改和询问一起进行二分答案的分治方法,本题整体二分模板题。
不过好像树状数组套主席树也能水过去。

代码:

整体二分:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
inline LL read(){
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=50005;
struct Oprt{
    int opt,l,r,no;
    LL k;
}q[MAXN],q1[MAXN],q2[MAXN];
int n,m,tot,sav[MAXN];
LL sum[MAXN*4],plu[MAXN*4],kk;int ql,qr;
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mid ((l+r)>>1)
void pushdown(int o,int l,int r){
    if(plu[o]==0) return;
    sum[lc]+=plu[o]*(mid-l+1);
    sum[rc]+=plu[o]*(r-mid);
    plu[lc]+=plu[o];
    plu[rc]+=plu[o];
    plu[o]=0; 
}
void upd(int o,int l,int r){
    if(ql<=l&&r<=qr){
        sum[o]+=kk*(r-l+1);
        plu[o]+=kk;
        return;
    }
    pushdown(o,l,r);
    if(mid>=ql) upd(lc,l,mid);
    if(mid<qr) upd(rc,mid+1,r);
    sum[o]=sum[lc]+sum[rc];
    
}
LL query(int o,int l,int r){
    if(ql<=l&&r<=qr){
        return sum[o];
    }
    pushdown(o,l,r);
    LL ans=0;
    if(mid>=ql) ans+=query(lc,l,mid);
    if(mid<qr) ans+=query(rc,mid+1,r);
    return ans;
}
#undef lc
#undef rc
void solve(int l,int r,int fs,int ls){
    if(fs>ls) return;
    if(l==r){
        for(int i=fs;i<=ls;i++)
            if(q[i].opt==2) sav[q[i].no]=l;
        return;
    }
    bool flag=0;
    for(int i=fs;i<=ls;i++)
        if(q[i].opt==2){
            flag=1;break;
        }
    if(!flag) return;
    int t1=0,t2=0;
    for(int i=fs;i<=ls;i++){
        if(q[i].opt==2){
            ql=q[i].l,qr=q[i].r;
            LL temp=query(1,1,n);
            if(temp>=q[i].k) q1[++t1]=q[i];
            else q[i].k-=temp,q2[++t2]=q[i];
        }
        else{
            if(q[i].k<=mid){
                ql=q[i].l,qr=q[i].r,kk=1;
                upd(1,1,n);
                q1[++t1]=q[i];
            }
            else q2[++t2]=q[i];
        }
    }
    for(int i=1;i<=t1;i++){
        if(q1[i].opt==1){
            ql=q1[i].l,qr=q1[i].r,kk=-1;
            upd(1,1,n);
        }
    }
    for(int i=1;i<=t1;i++) q[fs-1+i]=q1[i];
    for(int i=1;i<=t2;i++) q[fs+t1-1+i]=q2[i];
    solve(l,mid,fs,fs+t1-1);
    solve(mid+1,r,fs+t1,ls);
}
#undef mid
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        q[i].opt=read();
        q[i].l=read();
        q[i].r=read();
        q[i].k=read();
        if(q[i].opt==1) q[i].k=n-q[i].k+1;
        else q[i].no=++tot;
    }
    solve(-MAXN,MAXN,1,m);
    for(int i=1;i<=tot;i++){
        printf("%d\n",n-sav[i]+1);
    }
    return 0;
}

树套树(树状数组套主席树):

先挖一个坑

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9319984.html