zoukankan      html  css  js  c++  java
  • P3369 【模板】普通平衡树(Treap/SBT)

    题目描述

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

    1. 插入x数

    2. 删除x数(若有多个相同的数,因只删除一个)

    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)

    4. 查询排名为x的数

    5. 求x的前驱(前驱定义为小于x,且最大的数)

    6. 求x的后继(后继定义为大于x,且最小的数)

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

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

    说明

    时空限制:1000ms,128M

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

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

    来源:Tyvj1728 原名:普通平衡树

    在此鸣谢

    FHQ Treap。。。

    这是我迄今为止见过最神奇没有之一的数据结构!。

    它可以用简单的两个非旋转操作模拟出BST的所有操作。

    unbelievable。

    有空要好好写一篇关于这个的博客

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<cstdlib>
      7 #include<ctime>
      8 using namespace std;
      9 const int MAXN=100001;
     10 static void read(int &n)
     11 {
     12     char c='+';int x=0;bool flag=0;
     13     while(c<'0'||c>'9'){c=getchar();if(c=='-')flag=1;}
     14     while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c-48);c=getchar();}
     15     flag==1?n=-x:n=x;
     16 }
     17 int ch[MAXN][3];// 0左孩子 1右孩子
     18 int val[MAXN];// 每一个点的权值
     19 int pri[MAXN];// 随机生成的附件权值
     20 int siz[MAXN];// 以i为节点的树的节点数量
     21 int sz;// 总结点的数量 
     22 void update(int x)
     23 {
     24     siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];
     25 } 
     26 int new_node(int v)
     27 {
     28     siz[++sz]=1;// 新开辟一个节点
     29     val[sz]=v;
     30     pri[sz]=rand(); 
     31     return sz;
     32 }
     33 int merge(int x,int y)// 合并 
     34 {
     35     if(!x||!y)    return x+y;// x和y中必定有一个是0
     36     if(pri[x]<pri[y])// 把x加到左边的树上 
     37     {
     38         ch[x][1]=merge(ch[x][1],y);// 不懂的看GIF图 
     39         update(x);
     40         return x;
     41     } 
     42     else
     43     {
     44         ch[y][0]=merge(x,ch[y][0]);
     45         update(y);
     46         return y;
     47     }
     48 }
     49 void split(int now,int k,int &x,int &y)
     50 {
     51     if(!now) x=y=0;// 到达叶子节点
     52     else
     53     {
     54         if(val[now]<=k)// 分离右子树    
     55             x=now,split(ch[now][1],k,ch[now][1],y);
     56         else 
     57             y=now,split(ch[now][0],k,x,ch[now][0]);
     58         update(now);
     59     } 
     60 }
     61 int kth(int now,int k)// 查询排名 
     62 {
     63     while(1)
     64     {
     65         if(k<=siz[ch[now][0]])
     66             now=ch[now][0];// 在左子树中,且数量小于左子树的大小,迭代寻找
     67         else if(k==siz[ch[now][0]]+1)
     68             return now;// 找到了
     69         else 
     70             k-=siz[ch[now][0]]+1,now=ch[now][1];// 去右子树找 
     71     }
     72 }
     73 int main()
     74 {
     75     srand((unsigned)time(NULL));
     76     int n;
     77     read(n);
     78     int root=0,x,y,z;
     79     for(int i=1;i<=n;i++)
     80     {
     81         int how,a;
     82         read(how);read(a);
     83         if(how==1)// 插入 
     84         {
     85             split(root,a,x,y);
     86             root=merge(merge(x,new_node(a)),y);
     87         }
     88         else if(how==2)//删除x 
     89         {
     90             split(root,a,x,z);
     91             split(x,a-1,x,y);
     92             y=merge(ch[y][0],ch[y][1]);
     93             root=merge(merge(x,y),z);
     94         }
     95         else if(how==3)//查询x的排名 
     96         {
     97             split(root,a-1,x,y);
     98             printf("%d
    ",siz[x]+1);
     99             root=merge(x,y);
    100         }
    101         else if(how==4)// 查询排名为x的数 
    102         {
    103             printf("%d
    ",val[kth(root,a)]);
    104         }
    105         else if(how==5)// 求x的前驱 
    106         {
    107             split(root,a-1,x,y);
    108             printf("%d
    ",val[kth(x,siz[x])]);
    109             root=merge(x,y);
    110         }
    111         else if(how==6)// 求x的后继 
    112         {
    113             split(root,a,x,y);
    114             printf("%d
    ",val[kth(y,1)]);
    115             root=merge(x,y);
    116         }
    117     }
    118     return 0;
    119 }
  • 相关阅读:
    PTA —— 基础编程题目集 —— 函数题 —— 61 简单输出整数 (10 分)
    PTA —— 基础编程题目集 —— 函数题 —— 61 简单输出整数 (10 分)
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    迷宫问题 POJ 3984
    UVA 820 Internet Bandwidth (因特网带宽)(最大流)
    UVA 1001 Say Cheese(奶酪里的老鼠)(flod)
    UVA 11105 Semiprime Hnumbers(H半素数)
    UVA 557 Burger(汉堡)(dp+概率)
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/7151432.html
Copyright © 2011-2022 走看看