zoukankan      html  css  js  c++  java
  • BZOJ3224普通平衡树——非旋转treap

    题目:

    此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:
    1. 插入x数
    2. 删除x数(若有多个相同的数,因只删除一个)
    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
    4. 查询排名为x的数
    5. 求x的前驱(前驱定义为小于x,且最大的数)
    6. 求x的后继(后继定义为大于x,且最小的数)

    n<=100000 所有数字均在-107到107内。 

    输入样例:
    10
    1 106465
    4 1
    1 317721
    1 460929
    1 644985
    1 84185
    1 89851
    6 81968
    1 492737
    5 493598
    输出样例:
    106465
    84185
    492737

    变量声明:size[x],以x为根节点的子树大小;ls[x],x的左儿子;rs[x],x的右子树;r[x],x节点的随机数;v[x],x节点的权值。

    root,树的总根;tot,树的大小。

    非旋转treap不同于旋转treap需要靠旋转来维护平衡树的性质,他的操作可以用简单暴力来形容——只有合并和断裂两个操作。他不但有treap的优良性质,还有许多优点:支持可持久化和区间操作,常数比splay小。

    下面介绍一下非旋转treap的这两个操作:

    1.断裂

    就是去掉一条边,把treap拆分成两棵树,对于区间操作可以进行两次断裂来分割出一段区间再进行操作。

    以查找value为例,从root往下走,如果v[x]>value,那么下一步走ls[x],之后的点都比x小,把x接到右树上,下一次再接到右树上的点就是x的左儿子。

    v[x]<=value与上述类似,在这里不加赘述。

    void split(int x,int &lroot,int &rroot,int val)
    {
        if(!x)
        {
            lroot=rroot=0;
            return ;
        }
        if(v[x]<=val)
        {
            lroot=x;
            split(rs[x],rs[lroot],rroot,val);
        }
        else
        {
            rroot=x;
            split(ls[x],lroot,ls[rroot],val);
        }
        up(x);
    }

    2.合并

    就是把断裂开的树合并起来,因为要维护堆的性质所以按可并堆来合并。

    void merge(int &x,int a,int b)
    {
        if(!a||!b)
        {
            x=a+b;
            return ;
        }
        if(r[a]<r[b])
        {
            x=a;
            merge(rs[x],rs[a],b);
        }
        else
        {
            x=b;
            merge(ls[x],a,ls[b]);
        }
        up(x);
    }

    为了方便删除,所以建议把相同权值的点分开来加入树中,不要都放在同一个点。

    非旋转treap代码比较短(为了清晰我写的比较长qwq)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    using namespace std;
    int INF=1000000000;
    int n;
    int opt,x;
    int r[100010];
    int ls[100010];
    int rs[100010];
    int size[100010];
    int v[100010];
    int root;
    int tot;
    void up(int x)
    {
        size[x]=size[ls[x]]+size[rs[x]]+1;
    }
    void build(int &x,int val)
    {
        tot++;
        size[tot]=1;
        r[tot]=rand();
        v[tot]=val;
        ls[tot]=rs[tot]=0;
        x=tot;
    }
    void merge(int &x,int a,int b)
    {
        if(!a||!b)
        {
            x=a+b;
            return ;
        }
        if(r[a]<r[b])
        {
            x=a;
            merge(rs[x],rs[a],b);
        }
        else
        {
            x=b;
            merge(ls[x],a,ls[b]);
        }
        up(x);
    }
    void split(int x,int &lroot,int &rroot,int val)
    {
        if(!x)
        {
            lroot=rroot=0;
            return ;
        }
        if(v[x]<=val)
        {
            lroot=x;
            split(rs[x],rs[lroot],rroot,val);
        }
        else
        {
            rroot=x;
            split(ls[x],lroot,ls[rroot],val);
        }
        up(x);
    }
    void insert_sum(int val)
    {
        int x=0;
        int y=0;
        int z=0;
        build(z,val);
        split(root,x,y,val);
        merge(x,x,z);
        merge(root,x,y);
    }
    void delete_sum(int val)
    {
        int x=0;
        int y=0;
        int z=0;
        split(root,x,y,val);
        split(x,x,z,val-1);
        merge(z,ls[z],rs[z]);
        merge(x,x,z);
        merge(root,x,y);
    }
    void ask_rank(int val)
    {
        int x=0;
        int y=0;
        split(root,x,y,val-1);
        printf("%d
    ",size[x]+1);
        merge(root,x,y);
    }
    void ask_sum(int x,int num)
    {
        while(size[ls[x]]+1!=num)
        {
            if(num<=size[ls[x]])
            {
                x=ls[x];
            }
            else
            {
                num-=(size[ls[x]]+1);
                x=rs[x];
            }
        }
        printf("%d
    ",v[x]);
    }
    void ask_front(int val)
    {
        int x=0;
        int y=0;
        split(root,x,y,val-1);
        if(size[x]==0)
        {
            printf("0
    ");
        }
        else
        {
            ask_sum(x,size[x]);
        }
        merge(root,x,y);
    }
    void ask_back(int val)
    {
        int x=0;
        int y=0;
        split(root,x,y,val);
        ask_sum(y,1);
        merge(root,x,y);
    }
    int main()
    {
        srand(16);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&opt,&x);
            if(opt==1)
            {
                insert_sum(x);
            }
            else if(opt==2)
            {
                delete_sum(x);
            }
            else if(opt==3)
            {
                if(tot==0)
                {
                    printf("0
    ");
                }
                else
                {
                    ask_rank(x);
                }
            }
            else if(opt==4)
            {
                if(tot==0)
                {
                    printf("0
    ");
                }
                else
                {
                    ask_sum(root,x);
                }
            }
            else if(opt==5)
            {
                if(tot==0)
                {
                    printf("0
    ");
                }
                else
                {
                    ask_front(x);
                }
            }
            else if(opt==6)
            {
                if(tot==0)
                {
                    printf("0
    ");
                }
                else
                {
                    ask_back(x);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    蓝桥杯之递归算法基本框架

    Dubbo是什么
    java
    java
    java
    java
    java
    负载均衡的理解
    设计模式学习
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/8992409.html
Copyright © 2011-2022 走看看