LUOGU P3380 【模板】二逼平衡树(树套树)

传送门

解题思路

  这里写的是常数巨大的线段树套\(splay\),卡了半天常才过。首先线段树每个节点挂一个\(splay\)\(splay\)中的元素即为线段树管辖的区间中的数。对于操作\(1\),发现\(rk\)是可以求和的,所以直接在线段树上找到对应区间求\(rk\)即可,时间复杂度\(O(nlog^2n)\);对于操作\(2\),发现不具有可加性,所以要二分转化成求\(rk\),时间复杂度\(O(nlog^3n)\);对于操作\(3\),直接在线段树中找到对应区间,\(splay\)中删数加数即可,时间复杂度\(O(nlog^2n)\);对于操作\(4,5\),直接在对应后继然后取\(min\)\(max\)即可,时间复杂度\(O(nlog^2n)\)

代码

// luogu-judger-enable-o2
#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=50005;
const int M=N*40;
const int inf=2147483647;

inline int rd(){
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;
}
void out(int x){
    if(!x) return; out(x/10); putchar('0'+x%10);
}
inline void OUT(int x) {
    if(!x) putchar('0');
    else (x>0)?(out(x)):(putchar('-'),out(-x));
    putchar('\n');
}
inline int min(int x,int y) {return x<y?x:y;}
inline int max(int x,int y) {return x>y?x:y;}

int n,m,rt,tot=2,zz[N],ans,Max,Min=inf;

struct Splay{
    int val[M],ch[M][2],fa[M],siz[M],cnt[M],rt[M];
    inline bool check(int x){return (x==ch[fa[x]][1]);}
    inline void pushup(int x) {siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];}
    inline void rotate(int x){
        int y=fa[x],z=fa[y]; bool chk=check(x);
        if(z) ch[z][check(y)]=x; ch[y][chk]=ch[x][chk^1];
        fa[ch[x][chk^1]]=y; ch[x][chk^1]=y; fa[y]=x; fa[x]=z;
        pushup(y); pushup(x);
    }	
    inline void splay(int x,int top,int id){
        for(;fa[x]!=top;rotate(x))
            if(fa[fa[x]]!=top) rotate(check(fa[x])==check(x)?fa[x]:x);
        if(!top) rt[id]=x;
    }
    inline void find(int x,int y){
        int now=rt[y];
        while(1){
            if(val[now]==x) {splay(now,0,y); return;}
            if(x>val[now]) now=ch[now][1];
            else now=ch[now][0]; 
        }
    }
    inline int get_pre(int x){
        int now=ch[rt[x]][0]; if(!now) return 2;
        while(ch[now][1]) now=ch[now][1];
        return now; 
    }
    inline int get_nxt(int x){
        int now=ch[rt[x]][1]; if(!now) return 1;
        while(ch[now][0]) now=ch[now][0];
        return now;
    }
    inline void insert(int x,int y){
        if(!rt[x]) {rt[x]=++tot; val[tot]=y; siz[tot]=cnt[tot]=1; return;}
        register int now=rt[x],lst=0;
        while(1){
            if(val[now]==y) {cnt[now]++; splay(now,0,x); return;}
            lst=now; now=ch[now][y>val[now]];
            if(!now) {
                now=++tot; val[now]=y; cnt[now]=siz[now]=1;
                ch[lst][y>val[lst]]=now; fa[now]=lst;
                splay(now,0,x); return;
            }
        }
    }
    inline void erase(int x,int y){
        find(y,x); register int now=rt[x],Pre,Nxt;
        if(cnt[now]>1) cnt[now]--;
        else if(!ch[now][0] && !ch[now][1]) rt[x]=0;
        else if(!ch[now][0]) fa[ch[now][1]]=0,rt[x]=ch[now][1];
        else if(!ch[now][1]) fa[ch[now][0]]=0,rt[x]=ch[now][0];
        else {
            Pre=get_pre(x); Nxt=get_nxt(x);
            splay(Pre,0,x); splay(Nxt,Pre,x);
            ch[Nxt][0]=0; splay(Nxt,0,x);
        }	
    }
    inline int rk(int x,int y){
        register int now=rt[x],ret=0;
        while(1){
            if(!now) return ret;
            if(val[now]==y) {ret+=siz[ch[now][0]]; splay(now,0,x); return ret;}
            if(val[now]<y) ret+=siz[ch[now][0]]+cnt[now],now=ch[now][1];
            else now=ch[now][0];
        }
    }
}tree2;

struct Segment_Tree{
    #define mid ((l+r)>>1)
    int ls[M],rs[M];
    void update(int x,int l,int r,int pos,int w){
        tree2.insert(x,w); if(l==r) return;
        if(pos<=mid) update(x<<1,l,mid,pos,w);
        else update(x<<1|1,mid+1,r,pos,w);
    }
    void modify(int x,int l,int r,int pos,int w){
        tree2.erase(x,zz[pos]); tree2.insert(x,w); 
        if(l==r) return;
        if(pos<=mid) modify(x<<1,l,mid,pos,w);
        else modify(x<<1|1,mid+1,r,pos,w);
    }
    void query_rk(int x,int l,int r,int L,int R,int k){
//		if(L<=l && r<=R) cout<<l<<" "<<r<<" "<<x<<" "<<tree2.rk(x,k)<<endl;
        if(L<=l && r<=R) {ans+=tree2.rk(x,k); return; }
        if(L<=mid) query_rk(x<<1,l,mid,L,R,k);
        if(mid<R) query_rk(x<<1|1,mid+1,r,L,R,k);
    }
    void query_pre(int x,int l,int r,int L,int R,int k){
        if(L<=l && r<=R) {
            tree2.insert(x,k);
            ans=max(ans,tree2.val[tree2.get_pre(x)]);
            tree2.erase(x,k);
            return;
        }
        if(L<=mid) query_pre(x<<1,l,mid,L,R,k);
        if(mid<R) query_pre(x<<1|1,mid+1,r,L,R,k);
    }
    void query_nxt(int x,int l,int r,int L,int R,int k){
        if(L<=l && r<=R) {
            tree2.insert(x,k);
            ans=min(ans,tree2.val[tree2.get_nxt(x)]);
            tree2.erase(x,k);
            return;
        }
        if(L<=mid) query_nxt(x<<1,l,mid,L,R,k);
        if(mid<R) query_nxt(x<<1|1,mid+1,r,L,R,k);
    }
    #undef mid
}tree1;

inline int query_kth(int l,int r,int lim){
    int L=Min,R=Max,mid,ret;
    while(L<=R){
        mid=(L+R)>>1; ans=1; tree1.query_rk(1,1,n,l,r,mid);
        if(ans>lim) R=mid-1; else ret=mid,L=mid+1;
    }
    return ret;
}

int main(){
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
    tree2.val[2]=-inf; tree2.val[1]=inf;
    n=rd(),m=rd(); int x,l,r,k,opt,L,R;
    for(register int i=1;i<=n;++i) 	
        zz[i]=rd(),tree1.update(1,1,n,i,zz[i]),Max=max(Max,zz[i]),Min=min(Min,zz[i]);
    while(m--){
        opt=rd();
        if(opt==1){
            l=rd(),r=rd(),k=rd(); ans=1;
            tree1.query_rk(1,1,n,l,r,k);
            OUT(ans);
        }
        else if(opt==2){
            l=rd(),r=rd(),k=rd();
            OUT(query_kth(l,r,k));
        }
        else if(opt==3){
            x=rd(),k=rd();
            tree1.modify(1,1,n,x,k);
            zz[x]=k; Max=max(Max,k); Min=min(Min,k);
        }
        else if(opt==4){
            l=rd(),r=rd(),k=rd(); ans=-inf;
            tree1.query_pre(1,1,n,l,r,k);
            OUT(ans);
        }
        else if(opt==5){
            l=rd(),r=rd(),k=rd(); ans=inf;
            tree1.query_nxt(1,1,n,l,r,k);
            OUT(ans);
        }
    }
    return 0;
}
posted @ 2019-02-24 19:42  Monster_Qi  阅读(160)  评论(0编辑  收藏  举报