zoukankan      html  css  js  c++  java
  • 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('
    ');
    }
    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;
    }
    
  • 相关阅读:
    拥有最多糖果的孩子
    求1+2+…+n
    网络-中间代理
    Header中的Referer属性表示
    ios13.4post请求出现网错错误 network err
    10.8&10.10
    9.23&9.27
    9.16&9.19
    校内模拟赛划水报告(9.9,9.11)
    男人八题 划水题解
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10427546.html
Copyright © 2011-2022 走看看