• [模板]普通平衡树


    3224: Tyvj 1728 普通平衡树

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 24082  Solved: 11089
    [Submit][Status][Discuss]

    Description

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

    Input

    第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

    Output

    对于操作3,4,5,6每行输出一个数,表示对应答案

    Sample Input

    10
    1 106465
    4 1
    1 317721
    1 460929
    1 644985
    1 84185
    1 89851
    6 81968
    1 492737
    5 493598

    Sample Output

    106465
    84185
    492737

    HINT

    1.n的数据范围:n<=100000

    2.每个数的数据范围:[-2e9,2e9]

    $Treap$

    二叉搜索树+堆,将权值形成二叉搜索树,并且在随机$rand$第二关键字从而将其转成堆,并且在此时不破坏二叉搜索树。因为堆并且随机因素所以期望时间复杂度$O(nlog n)$

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<ctime>
    #include<climits>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int N=300001;
    struct node{
        int l,r,cnt,num,size,rnk;
    }tr[N];
    int n,root,tot;
    void update(int k){
        tr[k].size=tr[k].cnt;
        tr[k].size+=tr[tr[k].l].size;
        tr[k].size+=tr[tr[k].r].size;return;
    }
    void zag(int &k){
        int tp=tr[k].l;
        tr[k].l=tr[tp].r;
        tr[tp].r=k;
        tr[tp].size=tr[k].size;
        update(k);
        k=tp;
        return;
    }
    void zig(int &k){
        int tp=tr[k].r;
        tr[k].r=tr[tp].l;
        tr[tp].l=k;
        tr[tp].size=tr[k].size;
        update(k);
        k=tp;
        return;
    }
    void insert(int x,int &k){
        if(k==0){
            k=++tot;
            tr[k].cnt=tr[k].size=1;tr[k].num=x;
            tr[k].rnk=rand();
            return;
        }
        tr[k].size++;
        if(x==tr[k].num){tr[k].cnt++;return;}
        if(x<tr[k].num){
            insert(x,tr[k].l);
            if(tr[tr[k].l].rnk<tr[k].rnk)zag(k);
        }else{
            insert(x,tr[k].r);
            if(tr[tr[k].r].rnk<tr[k].rnk) zig(k);
        }
        return;
    }
    void del(int x,int &k){
        if(x==tr[k].num){
            if(tr[k].cnt>1){tr[k].size--,tr[k].cnt--;return;}
            if(tr[k].l*tr[k].r==0) {k=tr[k].l+tr[k].r;return;}
            if(tr[tr[k].l].rnk<tr[tr[k].r].rnk){zag(k);del(x,k);return;}
            else{zig(k);del(x,k);return;}
        }
        tr[k].size--;
        if(x<tr[k].num) del(x,tr[k].l);
        else del(x,tr[k].r);
        return;
    }
    int rank_x(int x,int k){
        if(x==tr[k].num) return tr[tr[k].l].size+1;
        if(x<tr[k].num) return rank_x(x,tr[k].l);
        return tr[tr[k].l].size+tr[k].cnt+rank_x(x,tr[k].r);
    }
    int rank(int x,int k){
        if(k==0) return 0;
        if(tr[tr[k].l].size<x&&tr[tr[k].l].size+tr[k].cnt>=x) return tr[k].num;
        if(x<=tr[tr[k].l].size) return rank(x,tr[k].l);
        return rank(x-tr[tr[k].l].size-tr[k].cnt,tr[k].r);
    }
    int pre(int x,int k){
        if(k==0) return INT_MIN;
        if(x<=tr[k].num) return pre(x,tr[k].l);
        return max(tr[k].num,pre(x,tr[k].r));
    }
    int nex(int x,int k){
        if(k==0) return INT_MAX;
        if(x>=tr[k].num) return nex(x,tr[k].r);
        return min(tr[k].num,nex(x,tr[k].l));
    } 
    int main(){
        srand(time(0));
        n=read();
        while(n--){
            int opt=read(),x=read();
            if(opt==1) insert(x,root);
            if(opt==2) del(x,root);
            if(opt==3) printf("%d
    ",rank_x(x,root));
            if(opt==4) printf("%d
    ",rank(x,root));
            if(opt==5) printf("%d
    ",pre(x,root));
            if(opt==6) printf("%d
    ",nex(x,root));
        }
        return 0;
    }
    View Code

    $Splay$

    $Splay$与$Treap$都是在二叉搜索树上维护树高,而$Treap$用第二关键字维护,而$Splay$巧妙的运用双旋维护,均摊时间复杂度是$O(n log  n)$,证明请读者自己证明。

  • 相关阅读:
    第四章作业
    第二章上机实验报告
    对二分法的理解和结对编程情况
    Mysql与sql server的列的合并
    C#中如何去除窗体默认的关闭按钮
    C# 实现WinForm窗口最小化到系统托盘代码,并且判断左右鼠标的事件
    running total sql 2012+
    Poqwe Pivot error
    事务
    ssis 导EXCEL ERROR
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/10190089.html
Copyright © 2020-2023  润新知