例题传送门

听YZ哥哥说Splay是一种很神奇的数据结构,所以学习了一下它的最基本操作。O(1)的Spaly。

伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(logn)内完成插入、查找和删除操作。它由丹尼尔·斯立特Daniel Sleator和罗伯特·恩卓·塔扬Robert Endre Tarjan在1985年发明的。
在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法, 在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。伸展树应运而生。伸展树是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。
它的优势在于不需要记录用于平衡树的冗余信息。
Splay是一种自调整数据结构,它的核心是Splay操作。
Splay操作是Rotate的升级版,该函数将子节点旋转到根,来保持Splay的复杂度。
//我们这里讲的是双旋Splay,之所以称为双旋,是因为在判断父子关系之前,要旋一次,共旋两次。
 
Splay操作要分两种情况讨论。
①当前要Splay的点和它的父亲及其父亲的父亲(如果它有父亲的父亲的话)在同一直线上,先旋它的父亲。
②当前要Splay的点和它的父亲及其父亲的父亲(如果它有父亲的父亲的话)不在在同一直线上,旋该节点。
 
插入:在插入节点后,记录插入节点的位置,Splay到根。
删除:先找到要删的节点,记录下来,没有就return。删除要分几种情况讨论;
        ①没有左右节点,直接clear根。
      ②只有左节点或右节点,用左或右节点将根覆盖,clear原来的根。
      ③既有左节点又有右节点,将root的前驱Splay到根,然后将root的右节点(原来的root)的右节点连接到root的右节点上就好了。
其他操作跟Treap相似。
 
code:

#include <cstdio>
#include <cstring>
using namespace std; int read()
{
char c;while(c=getchar(),(c<''||c>'')&&c!='-');
int x=,y=;c=='-'?y=-:x=c-'';
while(c=getchar(),c>=''&&c<='')x=x*+c-'';
return x*y;
} int N,dist; struct Splay{
int tr[][],v[],tot[];
int f[],fa[],root,cnt;
Splay(){
memset(tr,,sizeof tr);
memset(v,,sizeof v);
memset(tot,,sizeof tot);
memset(f,,sizeof f);
cnt=root=;
}//初始化 void clear(int x){tr[x][]=tr[x][]=f[x]=fa[x]=tot[x]=v[x]=;}//清除节点信息
void up(int x){f[x]=f[tr[x][]]+f[tr[x][]]+tot[x];}//更新节点信息
int get(int x){return tr[fa[x]][]==x;}//which son of father void rotate(int &x)
{
int ol=fa[x],olol=fa[ol],to=get(x);
tr[ol][to]=tr[x][to^];fa[tr[x][to^]]=ol;
fa[ol]=x;tr[x][to^]=ol;
fa[x]=olol;
if(olol)//如果该节点的父亲的父亲存在
tr[olol][tr[olol][]==ol]=x;
up(ol);up(x);//这里一定要先更新ol,在更新x,想想为什么
} void splay(int x)
{
for(int S;S=fa[x];rotate(x))//先旋x
if(fa[S])//S不为根
rotate((get(x)==get(S)?S:x));//判断是否三点一线
root=x;
} void insert(int &x,int val,int pos)
{
if(!x){//插入
x=++cnt;
f[x]=tot[x]=,v[x]=val,fa[x]=pos;
dist=x;//记录节点
return ;
}
if(val==v[x]){dist=x,tot[x]++;return ;}//有一样的数
insert(tr[x][val>v[x]],val,x);
up(x);//更新
return ;
} int QueryX(int x,int val)//查询x的排名
{
if(!x)return ;
if(val==v[x])return f[tr[x][]]+;
int to=val>v[x];
return QueryX(tr[x][to],val)+(to?f[tr[x][]]+tot[x]:);
}
int QueryK(int x,int kth)//查询排名为K的数
{
if(!x)return ;
if(kth<=f[tr[x][]])return QueryK(tr[x][],kth);
if(kth>f[tr[x][]]+tot[x])return QueryK(tr[x][],kth-(f[tr[x][]]+tot[x]));
return v[x];
} void pre(int x,int val)//前驱
{
if(!x)return ;
if(val<=v[x])return pre(tr[x][],val);
else dist=x,pre(tr[x][],val);
}
void bac(int x,int val)//后继
{
if(!x)return ;
if(v[x]<=val)bac(tr[x][],val);
else dist=x,bac(tr[x][],val);
} int find(int x,int val)//在del之前先找节点,记录,并Splay
{
if(!x)return ;
if(v[x]==val){splay(x);return x;}//找到
int to=val>v[x];
return find(tr[x][to],val);
}
void del(int x)//删除
{
int kkk=find(root,x);
if(!kkk)return ;//不存在
if(tot[root]>){
tot[root]--,up(root);
return ;
}
if(!tr[root][]&&!tr[root][]){
clear(root),root=;
return ;
}
if(!(tr[root][]*tr[root][])){
int rt=root;
root=tr[root][]+tr[root][];
fa[root]=,clear(rt);//细节是要先记录root,再更新root,再将原来的root clear
return ;
}
int ok=root;//原来的root
pre(root,x);//求前驱
splay(dist);//Splay到根
fa[tr[ok][]]=root;
tr[root][]=tr[ok][];
clear(ok);up(root);fa[root]=;//clear,更新,细节是要把新根的fa清零
return ;
} }W; int main()
{
N=read();
while(N--){
int o=read(),x;
switch(o){
case :W.insert(W.root,read(),);W.splay(dist);break;
case :W.del(read());break;
case :printf("%d\n",W.QueryX(W.root,read()));break;
case :printf("%d\n",W.QueryK(W.root,read()));break;
case :dist=,W.pre(W.root,read());printf("%d\n",W.v[dist]);break;
case :dist=,W.bac(W.root,read());printf("%d\n",W.v[dist]);break;
}
}
}

Splay初学习的更多相关文章

  1. clisp, scheme 和 clojure 初学习

    clisp, scheme和clojure 初学习 1 clojure "clojure绝对会成为你的编程工具箱里的终极武器" "其他语言可能只是工具,但 Clojure ...

  2. c# window服务-初学习

    window服务-初学习 一.工具: VS2015+NET Framework4.5. 二.操作: 1.新建windows服务的项目: 2.修改windows服务相关内容: 3.预览windows服务 ...

  3. Python初学习:简单的练习题

    Python初学习 一些见到那的练习题: 初级难度 设计一重量转换器,输入以g为单位的数字后,返回换算结果以Kg为单位的结果 中级难度 设计一个求直角三角形斜边长的函数,(以两个直角边为参数,求最长边 ...

  4. BST,Splay平衡树学习笔记

    BST,Splay平衡树学习笔记 1.二叉查找树BST BST是一种二叉树形结构,其特点就在于:每一个非叶子结点的值都大于他的左子树中的任意一个值,并都小于他的右子树中的任意一个值. 2.BST的用处 ...

  5. [普通平衡树splay]【学习笔记】

    参考: http://blog.csdn.net/clove_unique/article/details/50630280 gty课件 找一个好的风格太难了,自己习惯用struct,就强行用stru ...

  6. Swift初学习

    距离swift发布10天了,也简单看了一下swift的语法,个人感觉相对于object-c很是简单明了.Swift的出现并不能说明iOS开发简单了很多,有可能会变得复杂,你需要学习两门编程语言,因为在 ...

  7. Jquery 插件初学习

    参考文章:插件开发精品教程,让你的jQuery提升一个台阶 刚刚学了一下jquery的插件插件开发,写个demo记录.练习一下.毕竟,输出才是最好的学习. 这个也不过是最基础的一个插件写法,只是,自己 ...

  8. requests库写接口测试框架初学习

    学习网址:    https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dscpm/ff75b907-415d-4220-89 ...

  9. 2018.2.21 Python 初学习

    折腾了一天,一直在用CMD学习Python写Hello World.偶然间发现可以用Pycharm.也算是给后面想学习的人提个醒,方便省事许多. format()使用方法. age = 20name ...

随机推荐

  1. 发布Hessian服务作为服务内部基础服务

    摘要:Hessian经常作为服务内部RPC工具来使用,速度快效率高.重构代码的核心思想就是把共用的代码段提出来,使代码结构优化:架构设计类似,把基本的共用的服务提出来,使架构优化.下面讲述一下我在具体 ...

  2. RabbitMQ Windows环境搭建

    1.0 RabbitMQ是用Erlang语言编写,因此安装RabbitMQ,首先要安装Erlang. Erlang的官网:http://www.erlang.org/ 文件:otp_win64_19. ...

  3. MaBatis(5)输入/输出映射

    本次全部学习内容:MyBatisLearning   输入映射: 通过parameType指定输入参数的类型,类型可以是简单类型,hashmap,pojo等     传递pojo的包装对象 需求: 即 ...

  4. fullCalendar日程管理

    //日程安排 function timeTable(id){ var inner = "<div id='calendar'></div>"; $(&quo ...

  5. iOS一个很好的内存检测工具

    虽然Xcode提供了instrument来检测内存,但是使用起来怎么看都很麻烦.然后有一个很不错的内存泄露的检测工具MLeaksFinder,使用的话不需要注入任何代码,直接导入库就行了.出现泄露的时 ...

  6. Vue教程:指令与事件(二)

    一.插值 v-once 通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新.但请留心这会影响到该节点上所有的数据绑定: span v-once>这个将不会改 ...

  7. enmu枚举类型

    在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把这些量说明为整型,字符型或其它类型显然是不妥当的.为此,C语言提供了一 ...

  8. java模拟浏览器发送请求

    package test; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOExcep ...

  9. Zookeeper简介和安装(四)

    一.简介: Zookeeper是一个分布式协调服务,提供的服务如下: 命名服务:类似于DNS,但仅对于节点 配置管理:服务配置信息的管理 集群管理:Dubbo使用Zookeeper实现服务治理 分布式 ...

  10. Oracle 缓存命中率问题一则(里面有个问题咨询大佬们)

    近日,核心数据库频繁抱出数据库缓存命中率过低,于是开始进行排查. 1.监控软件告警信息 2.抓取告警时间段内的awr报告进行分析 3.execute与parse命中率过低,说明分析(硬解析与软解析)的 ...