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/ +

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

  • 相关阅读:
    零基础转IT,我推荐你学习这三门技术
    蜗牛学院行内人分析:参加IT培训,大家一定要注意这五点!
    蜗牛学院分析:Web前端开发的就业前景怎么样,薪资待遇如何?
    软件测试和测试开发有什么区别?
    转行者越来越多,程序员是不是不值钱了呢?
    蜗牛学院卿老师:Python中几个比较容易混淆的概念解释
    webpack4.x的css单独打包、合并、自动添加前缀、压缩
    webpack4的splitChunksPlugin配置参数详解---代码分割 、懒加载以及prefetching 和 preloading
    vue列表页进入详情页,返回列表项不刷新
    js数组去重
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8973079.html
Copyright © 2011-2022 走看看