zoukankan      html  css  js  c++  java
  • [模板]普通平衡树

    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)$,证明请读者自己证明。

  • 相关阅读:
    leetcode 279. Perfect Squares
    leetcode 546. Remove Boxes
    leetcode 312. Burst Balloons
    leetcode 160. Intersection of Two Linked Lists
    leetcode 55. Jump Game
    剑指offer 滑动窗口的最大值
    剑指offer 剪绳子
    剑指offer 字符流中第一个不重复的字符
    leetcode 673. Number of Longest Increasing Subsequence
    leetcode 75. Sort Colors (荷兰三色旗问题)
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/10190089.html
Copyright © 2011-2022 走看看