例题传送门

听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. 利用Kali进行WiFi钓鱼测试实战

    文中提及的部分技术可能带有一定攻击性,仅供安全学习和教学用途,禁止非法使用.请不要做一只咖啡馆里安静的猥琐大叔. 写在前面 从至少一年前我就一直想在自己跑kali的笔记本上架个钓鱼热点.然而由于网上的 ...

  2. swift的动态库

    共享可执行文件 iOS 有沙箱机制,不能跨App间共享共态库,但Apple开放了App Extension,可以在App和Extension间共间动态库(这也许是Apple开放动态链接库的唯一原因了) ...

  3. BZOJ1770:[USACO]lights 燈(高斯消元,DFS)

    Description 貝希和她的閨密們在她們的牛棚中玩遊戲.但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了.貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望. ...

  4. 在.Net项目中使用Redis作为缓存服务

    转自:http://www.cnblogs.com/hohoa/p/5771255.html 最近由于项目需要,在系统缓存服务部分上了redis,终于有机会在实际开发中玩一下,之前都是自己随便看看写写 ...

  5. Kali-linux应用更新和配置额外安全工具

    本节将介绍更新Kali的过程和配置一些额外的工具.这些工具在后面的章节中将是有用的.Kali软件包不断地更新和发布之间,用户很快发现一套新的工具比最初在DVD ROM上下载的软件包更有用.本节将通过更 ...

  6. 【题解】洛谷P2827 [NOIP2016TG] 蚯蚓(优先队列)

    题目来源:洛谷P2827 思路 阅读理解题 一开始以为是裸的优先队列而已 但是发现维护一个切开并且其他的要分别加上一个值很不方便 而且如果直接用优先队列会TLE3到4个点 自测85分 所以我们需要发现 ...

  7. 关于session序列化和session钝化和活化

    在第一次启动服务器后,在session中放入一个对象.在页面可以获得,当重启服务器,但是没有关闭浏览器的情况下刷新页面仍然能够获得这个对象,前提是这个对象必须实现了java.io.Serializab ...

  8. 关于JS的clone()函数编写的一些问题

    问题讲述:用js 实现一个clone()克隆函数,该函数会把输入进去的不同类型值Number,String,Undefined,Boolean,Function,Null,Object,Array,R ...

  9. Oracle中常用的语句

    1.查询锁表 SELECT a.object_name,b.session_id,c.serial#,c.program,c.username,c.command,c.machine,c.lockwa ...

  10. dubbo配置注意

    API接口的路径在provider和consumer端的路径要一致