zoukankan      html  css  js  c++  java
  • BZOJ3196 & 洛谷3380:二逼平衡树——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3196

    https://www.luogu.org/problemnew/show/P3380

    (题面用洛谷的)

    您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

    1. 查询k在区间内的排名

    2. 查询区间内排名为k的值

    3. 修改某一位值上的数值

    4. 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

    5. 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

    参考:https://blog.csdn.net/clove_unique/article/details/51279573

    其实看参考博客就行了,线段树套splay极限卡时间。

    简单解释一下第二种操作:

    因为线段树没法查这个,所以一种直观的想法是二分答案。

    但由于周多麻烦的因素,我们存所有元素再排个序的效率并不高,于是我们直接对值域二分。

    但是显然有些值在这里面是没有的,所以要有一种很妙的判断手段。

    我们对于mid求出它在区间内之前有多少值,和k比较,如果比k小就不要。

    这样最后我们应该能够找到比该元素小的数有k+1个且最小的元素,且并不难证明这个元素-1的值一定在树中有。

    (因为这个元素-1如果不存在的话就应该有k+1个比它小,和“最小的元素”矛盾。)

    (人生第一棵树套树,感觉良好,卡常卡的质疑人生。)

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int INF=2147483647;
    const int N=4e6+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(ch<'0'||ch>'9'){w|=ch=='-';ch=getchar();}
        while(ch>='0'&&ch<='9')X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int s[N],maxn,rt[N],sz;
    int fa[N],tr[N][2],key[N],size[N],cnt[N];
    inline bool get(int x){
        return tr[fa[x]][1]==x;
    }
    inline void clear(int x){
        fa[x]=tr[x][0]=tr[x][1]=key[x]=cnt[x]=size[x]=0;
    }
    inline void splay_upd(int x){
        if(!x)return;
        size[x]=cnt[x];  
        if(tr[x][0])size[x]+=size[tr[x][0]];  
        if(tr[x][1])size[x]+=size[tr[x][1]];
    }
    inline void rotate(int x){
        int y=fa[x],z=fa[y],which=get(x);
        tr[y][which]=tr[x][which^1];fa[tr[y][which]]=y;  
        fa[y]=x;tr[x][which^1]=y;fa[x]=z;
        if(z)tr[z][tr[z][1]==y]=x;
        splay_upd(y);splay_upd(x);
    }
    inline void splay(int i,int x){
        int f=fa[x];
        while(f){
            if(fa[f])rotate(get(x)==get(f)?f:x);
            rotate(x);f=fa[x];
        }
        rt[i]=x;
    }
    inline void splay_ins(int i,int v){
        if(!rt[i]){
            rt[i]=++sz;
            fa[sz]=tr[sz][0]=tr[sz][1]=0;
            size[sz]=cnt[sz]=1;key[sz]=v;
            return;
        }
        int now=rt[i],f=0;
        while(233){
            if(key[now]==v){
                cnt[now]++;splay_upd(f);splay(i,now);
                return;
            }
            f=now;now=tr[now][key[now]<v];
            if(!now){
                ++sz;
                fa[sz]=f;tr[sz][0]=tr[sz][1]=0;
                    size[sz]=cnt[sz]=1;key[sz]=v;
                tr[f][key[f]<v]=sz;
                splay_upd(f);splay(i,sz);
                return;
            }
        }
    }
    inline int splay_find(int i,int v){//查询比v小的数的个数 
        int ans=0,now=rt[i];
        while(233){
            if(!now)return ans;
            if(v<key[now])now=tr[now][0];
            else{
                ans+=(tr[now][0]?size[tr[now][0]]:0);
                if(v==key[now]){
                    splay(i,now);
                    return ans;
                }
                ans+=cnt[now];
                now=tr[now][1];
            }
        }
    }
    inline int splay_pre(int i){
        int now=tr[rt[i]][0];
        while(tr[now][1])now=tr[now][1];
        return now;
    }
    inline int splay_nxt(int i){
        int now=tr[rt[i]][1];
        while(tr[now][0])now=tr[now][0];
        return now;
    }
    inline void splay_del(int i,int x){
        splay_find(i,x);
        if(cnt[rt[i]]>1){
            cnt[rt[i]]--;return;
        }
        if(!tr[rt[i]][0]&&!tr[rt[i]][1]){
            clear(rt[i]);rt[i]=0;return;
        }
        if(!tr[rt[i]][0]){  
            int oldroot=rt[i];rt[i]=tr[rt[i]][1];fa[rt[i]]=0;clear(oldroot);return;
        }
        else if(!tr[rt[i]][1]){  
            int oldroot=rt[i];rt[i]=tr[rt[i]][0];fa[rt[i]]=0;clear(oldroot);return;
        }
        int leftbig=splay_pre(i),oldroot=rt[i];  
        splay(i,leftbig);
        fa[tr[oldroot][1]]=rt[i];
        tr[rt[i]][1]=tr[oldroot][1];
        clear(oldroot);
        splay_upd(rt[i]);
    }
    inline void seg_mdy(int a,int l,int r,int x,int v){
        splay_del(a,s[x]);splay_ins(a,v);
        if(l==r)return;
        int mid=(l+r)>>1;
        if(x<=mid)seg_mdy(a<<1,l,mid,x,v);
        else seg_mdy(a<<1|1,mid+1,r,x,v);
    }
    inline int seg_find(int a,int l,int r,int l1,int r1,int v){
        if(r<l1||r1<l)return 0;
        if(l1<=l&&r<=r1)return splay_find(a,v);
        int mid=(l+r)>>1;
        return seg_find(a<<1,l,mid,l1,r1,v)+seg_find(a<<1|1,mid+1,r,l1,r1,v);
    }
    inline int seg_pre(int a,int l,int r,int l1,int r1,int v){
        if(r<l1||r1<l)return -INF;
        if(l1<=l&&r<=r1){
            splay_ins(a,v);
            int tmp=splay_pre(a);
            splay_del(a,v);
            return !tmp?-INF:key[tmp];
        }
        int mid=(l+r)>>1;
        return max(seg_pre(a<<1,l,mid,l1,r1,v),seg_pre(a<<1|1,mid+1,r,l1,r1,v));
    }
    inline int seg_nxt(int a,int l,int r,int l1,int r1,int v){
        if(r<l1||r1<l)return INF;
        if(l1<=l&&r<=r1){
            splay_ins(a,v);
            int tmp=splay_nxt(a);
            splay_del(a,v);
            return !tmp?INF:key[tmp];
        }
        int mid=(l+r)>>1;
        return min(seg_nxt(a<<1,l,mid,l1,r1,v),seg_nxt(a<<1|1,mid+1,r,l1,r1,v));
    }
    inline void seg_build(int a,int l,int r){
        for(int i=l;i<=r;i++)splay_ins(a,s[i]);
        if(l==r)return;
        int mid=(l+r)>>1;
        seg_build(a<<1,l,mid);seg_build(a<<1|1,mid+1,r);
    }
    int main(){
        int n=read(),m=read();
        for(int i=1;i<=n;++i){
            s[i]=read(),maxn=max(maxn,s[i]);
        }
        seg_build(1,1,n);
        for(int i=1;i<=m;++i){
            int op=read();
            if(op==1){
                int l=read(),r=read(),k=read();
                printf("%d
    ",seg_find(1,1,n,l,r,k)+1);
            }
            if(op==2){
                int l=read(),r=read(),k=read();
                int l1=0,r1=maxn+1;
                while(l1<r1){
                    int mid=(l1+r1)>>1;
                    int rk=seg_find(1,1,n,l,r,mid);
                    if(rk<k)l1=mid+1;
                    else r1=mid;
                }
                printf("%d
    ",l1-1);
            }
            if(op==3){
                int pos=read(),k=read();
                seg_mdy(1,1,n,pos,k);
                s[pos]=k;maxn=max(maxn,s[pos]);
            }
            if(op==4){
                int l=read(),r=read(),k=read();
                printf("%d
    ",seg_pre(1,1,n,l,r,k)); 
            }
            if(op==5){
                int l=read(),r=read(),k=read();
                printf("%d
    ",seg_nxt(1,1,n,l,r,k)); 
            }
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    numpy 基础 —— np.linalg
    图像旋转后显示不完全
    opencv ---getRotationMatrix2D函数
    PS1--cannot be loaded because the execution of scripts is disabled on this system
    打开jnlp Faild to validate certificate, the application will not be executed.
    BATCH(BAT批处理命令语法)
    oracle vm virtualbox 如何让虚拟机可以上网
    merge 实现
    Windows batch,echo到文件不成功,只打印出ECHO is on.
    python2.7.6 , setuptools pip install, 报错:UnicodeDecodeError:'ascii' codec can't decode byte
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8973079.html
Copyright © 2011-2022 走看看