• 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 原名:普通平衡树

    在此鸣谢

    我的天,,splay这种东西直接要人命,,

    思路比KMP好想,代码比DP简单。

    但是调试。。。。。。

    呵呵,,,,,

    至于怎么做:

    https://www.luogu.org/wiki/show?name=%E9%A2%98%E8%A7%A3+P3369

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 using namespace std;
      6 const int MAXN=100005;
      7 const int maxn=0x7fffffff;
      8 void read(int &n)
      9 {
     10     char c='+';int x=0;bool flag=0;
     11     while(c<'0'||c>'9'){c=getchar();if(c=='-')flag=1;}
     12     while(c>='0'&&c<='9'){x=x*10+(c-48);c=getchar();}
     13     flag==1?n=-x:n=x;
     14 }
     15 struct SPLAY
     16 {
     17     #define root e[0].ch[1]
     18     struct node
     19     {
     20         int v;// 节点的权值 
     21         int fa;
     22         int ch[2];
     23         int sum;// 当前节点的子树的元素
     24         int recy;// 当前节点重复的次数 
     25     };
     26     node e[MAXN];
     27     int tot,points;
     28     SPLAY()
     29     {
     30         tot=0;points=0;
     31     }
     32     void update(int pos)// 上传标记 
     33     {
     34         e[pos].sum=e[e[pos].ch[0]].sum+e[e[pos].ch[1]].sum+e[pos].recy;
     35     }
     36     int identify(int x)//找到编号为x的节点是他的父亲的左孩子节点还是右孩子节点 
     37     {
     38         return e[e[x].fa].ch[0]==x?0:1;
     39     }
     40     int connect(int son,int father,int how)// 把编号为son的节点连接到编号为father的节点的how孩子 
     41     {
     42         e[son].fa=father;
     43         e[father].ch[how]=son;
     44     }
     45     void rotate(int x)//双旋 
     46     {
     47         int y=e[x].fa;
     48         int R=e[y].fa;
     49         int Rson=identify(y);
     50         int yson=identify(x);
     51         int B=e[x].ch[yson^1];
     52         connect(B,y,yson);
     53         connect(y,x,(yson^1));
     54         connect(x,R,Rson);
     55         update(y);update(x);
     56     }
     57     void Splay(int pos,int to)// 把编号为pos的节点旋转到编号为to的节点 
     58     {
     59          to=e[to].fa;
     60         while(e[pos].fa!=to)
     61         {
     62             int up=e[pos].fa;
     63             if(e[up].fa==to)    rotate(pos);
     64             else if(identify(up)==identify(pos))
     65             {
     66                 rotate(up);
     67                 rotate(pos);
     68             }
     69             else
     70             {
     71                 rotate(pos);
     72                 rotate(pos);
     73             }
     74         }
     75     }
     76 
     77     int crepoint(int v,int father)// 新建一个节点 
     78     {
     79         tot++;
     80         e[tot].fa=father;
     81         e[tot].recy=e[tot].sum=1;
     82         e[tot].v=v;
     83         return tot;
     84     }
     85     void destroy(int x)// 直接摧毁一个节点 
     86     {
     87         e[x].ch[0]=e[x].ch[1]=e[x].fa=e[x].recy=e[x].sum=e[x].v=0;
     88         if(x==tot)    tot--;
     89     }
     90     int find(int v)// 找到 权值为v的点所在的位置 
     91     {
     92         int now=root;
     93         while(1)
     94         {
     95             if(e[now].v==v)
     96             {
     97                 Splay(now,root);
     98                 return now;
     99             }
    100             int nxt=v<e[now].v?0:1;
    101             if(!e[now].ch[nxt])return 0;
    102             now=e[now].ch[nxt];
    103         }
    104     }
    105     int build(int v)// 新开一个节点 
    106     {
    107         points++;
    108         if(tot==0)
    109         {
    110             root=1;
    111             crepoint(v,0);
    112         }
    113         else
    114         {
    115             int now=root;
    116             while(1)
    117             {
    118                 e[now].sum++;// 经过的路径上的点的子树的元素一定会++ 
    119                 if(e[now].v==v)
    120                 {
    121                     e[now].recy++;
    122                     return now;
    123                 }
    124                 int nxt=v<e[now].v?0:1;
    125                 if(!e[now].ch[nxt])
    126                 {
    127                     crepoint(v,now);
    128                     e[now].ch[nxt]=tot;
    129                     return tot;
    130                 }
    131                 now=e[now].ch[nxt];
    132             }
    133         }
    134         return 0;//what....
    135     }
    136     int push(int v)// 新开一个节点并旋转到根 
    137     {
    138         int p=build(v);
    139         Splay(p,root);
    140     }
    141     void pop(int v)// 删除节点,并调整树的结构 
    142     {
    143         int deal=find(v);
    144         if(!deal)    return ;
    145         points--;
    146         if(e[deal].recy>1)
    147         {
    148             e[deal].recy--;
    149             e[deal].sum--;
    150              return;
    151         }
    152         if(!e[deal].ch[0])
    153         {
    154             root=e[deal].ch[1];
    155             e[root].fa=0;
    156         }
    157         else
    158         {
    159             int le=e[deal].ch[0];
    160             while(e[le].ch[1])
    161                 le=e[le].ch[1];
    162             
    163             Splay(le,e[deal].ch[0]);
    164             
    165             int ri=e[deal].ch[1];
    166             connect(ri,le,1);
    167             connect(le,0,1);
    168             update(le);
    169         }
    170         destroy(deal);
    171     } 
    172     int rank(int v)// 查询值为v的数的排名 
    173     {
    174         int ans=0,now=root;
    175         while(1)
    176         {
    177             if(e[now].v==v)
    178                 return ans+e[e[now].ch[0]].sum+1;
    179             if(now==0)return 0;
    180             if(v<e[now].v)    now=e[now].ch[0];
    181             else
    182             {
    183                 ans+=e[e[now].ch[0]].sum+e[now].recy;
    184                 now=e[now].ch[1];
    185             }
    186             
    187         }
    188         if(now)    Splay(now,root);
    189         return 0;
    190     }
    191     int arank(int x)//查询排名为x的数是什么 
    192     {
    193         if(x>points)    return -maxn;
    194         int now=root;
    195         while(1)
    196         {
    197             int used=e[now].sum-e[e[now].ch[1]].sum;
    198             if(x>e[e[now].ch[0]].sum&&x<=used)break;
    199             if(x<used)
    200                 now=e[now].ch[0];
    201             else
    202             {
    203                 x=x-used;
    204                 now=e[now].ch[1];
    205             }
    206         }
    207         Splay(now,root);
    208         return e[now].v;
    209     }
    210     int lower(int v)// 小于v的最大值 
    211     {
    212         int now=root;
    213         int ans=-maxn;
    214         while(now)
    215         {
    216             if(e[now].v<v&&e[now].v>ans)    ans=e[now].v;
    217             if(v>e[now].v)    now=e[now].ch[1];
    218             else    now=e[now].ch[0];
    219         }
    220         return ans;
    221     }
    222     int upper(int v)
    223     {
    224         int now=root;
    225         int ans=maxn;
    226         while(now)
    227         {
    228             if(e[now].v>v&&e[now].v<ans)    ans=e[now].v;
    229             if(v<e[now].v)    now=e[now].ch[0];
    230             else    now=e[now].ch[1];
    231         }
    232         return ans;
    233     }
    234 };
    235 SPLAY s;
    236 int main()
    237 {
    238     
    239     int n;
    240     read(n);
    241     for(int i=1;i<=n;i++)
    242     {
    243         int opt,x;
    244         read(opt);read(x);
    245         if(opt==1)
    246             s.push(x);
    247         else if(opt==2)
    248             s.pop(x);
    249         else if(opt==3)
    250             printf("%d
    ",s.rank(x));
    251         else if(opt==4)
    252             printf("%d
    ",s.arank(x));
    253         else if(opt==5)
    254             printf("%d
    ",s.lower(x));
    255         else if(opt==6)
    256             printf("%d
    ",s.upper(x));
    257     }
    258     return 0;
    259 }
  • 相关阅读:
    JS第二天
    ES6
    Asp.net Core Web Mvc项目添加Jwt验证
    .Net Core 平台下创建WinForm窗体SignalR客户端
    .Net Core平台下实现SignalR客户端和服务端
    .Net Framework 平台下创建WinForm窗体SignalR客户端
    在.Net Framework平台下WPF实现SignalR客户端
    .Net Framework框架下实现SignalR客户端和服务端
    信息系统项目管理师10大管理47个过程域输入输出工具(项目人力资源管理)
    信息系统项目管理师10大管理47个过程域输入输出工具(项目质量管理)
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/7252079.html
Copyright © 2020-2023  润新知