浅谈splay
\(BST\)
二叉查找树,首先它是一颗二叉树,其次它里面每个点都满足以该点左儿子为根的子树里结点的值都小于自己的值,以该点右儿子为根的子树里结点的值都大于自己的值。如果不进行修改,每次查询都是\(O(logn)\)的。
\(Splay\)
\(splay\)是一种支持旋转的二叉查找树,由于旋转可以维护它的深度,使其保持平衡,所以我们又称它为平衡树。一般的平衡树支持的操作它基本都支持,不支持的比如有可持久化。所以我们不多赘述,直接讲它的特性:
旋转
\(zig和zag\)
单次旋转。若一个点是它父亲的左儿子,把它旋转上去,让它父亲成为它的右儿子,则称为\(zig\),否则称为\(zag\)。
根据下面这张图我们可以很好的理解\(zig\)和\(zag\)。

然后这两种单旋操作配合起来一共有四种双旋操作,分别是\(zig-zig\),\(zig-zag\),\(zag-zig\),\(zag-zag\)。
如果你觉得很烦,那你千万不要离开,因为本篇博客,就是来帮助你解忧的。
双旋单旋分情况讨论记不清怎么办?来来来,继续往下看,妈妈绝对不会再担心你的\(splay\)写挂了。
对于一次旋转,只会影响的四个结点,分别是\(x\)本身,\(x\)的父亲\(fa\),\(x\)的儿子\(s\),\(fa\)的父亲\(ffa\)。
设\(t(x)\)为\(x\)与其父亲的关系,左儿子为\(0\),右儿子为\(1\),那么\(t(s)=t(x)xor\) \(1\)。
第一步:把\(fa\)扳下来。
先确定\(fa\)与\(s\)的双方关系,\(fa\)在\(t(x)\)方向上认\(s\)做儿子,\(s\)认\(fa\)做父亲。然后按照此步骤确定\(x\)与\(fa\)的双方关系。
第二步:把\(x\)送上去。
确定\(x\)与\(ffa\)的双方关系。
代码如下:
int t(int u){return son[fa[u]][1]==u;}
void rotate(int u){
int ret=t(u),f=fa[u],s=son[u][ret^1];
int ffa=fa[f],ret_f=t(f);
son[f][ret]=s;if(s)fa[s]=f;//确立s与fa的关系
son[u][ret^1]=f;fa[f]=u;//确立u与fa的关系
fa[u]=ffa;if(ffa)son[ffa][ret_f]=u;//确立u与ffa的关系
}
至此,单旋操作就没了,是不是非常简单呢?
\(splay\)
\(splay\)操作就是让一个点\(x\)一直旋转一直旋转直到它到根为止。有单旋和双旋两种操作,单旋就是直接\(while\)循环调用上面那段代码就行了,双旋有四种情况,但是总的来说也只有两种。
当\(t(x)==t(fa)\)时,那就先单旋\(fa\),否则单旋一次\(x\)。
不管上面那个条件满不满足,都在第二次单旋一次\(x\)。
代码如下:
void splay(int u){
while(fa[u]){//有父亲就不是根
if(fa[fa[u]]){//可以双旋
if(t(fa[u])==t(u))rotate(fa[u]);
else rotate(u);//如上所述
}rotate(u);
}root=u;//旋转到根之后更新根
}
至此,\(splay\)的旋转操作就到此为止了,怎么样,是不是很简单呢?
哦对了,\(splay\)的复杂度十分玄学,在势能分析上来说,应该是\(log\)的,但是保持这个势能需要多多\(splay\),插入要\(splay\),删除也要\(splay\)。
插入
找到一个整个树里面权值最接近插入结点权值的点,然后把要插入的点给它做儿子,然后\(splay\)到根。
删除
把要删除的点\(splay\)到根,然后把它左儿子子树里最大的值旋到根的左儿子处,断开要删除的点的周边所有关系,把右子树的根接在左子树最大值右儿子处即可。
若需区间删除,则把\(l-1splay\)到根,把\(r+1splay\)到根的右儿子处,然后整个右儿子的左子树全部扔掉即可。
大多数时刻区间翻转区间加等操作都是这样,把要处理的区间这样放在根的右儿子的左子树处,然后直接打标记即可,这里我们就不多说了。
模板:https://www.cnblogs.com/AKMer/p/9985277.html
区间操作模板:https://www.cnblogs.com/AKMer/p/9987089.html
浅谈splay的更多相关文章
- 浅谈splay(点的操作)
浅谈splay(点的操作) 一.基本概念 splay本质:二叉查找树 特点:结点x的左子树权值都小于x的权值,右子树权值都大于x的权值 维护信息: 整棵树:root 当前根节点 sz书上所有结点编号 ...
- 浅谈splay的双旋
昨晚终于明白了splay双旋中的一些细节,今日整理如下 注:题目用的2002HNOI营业额统计,测试结果均来及codevs 网站的评测结果 http://codevs.cn/problem/1296/ ...
- 简析平衡树(三)——浅谈Splay
前言 原本以为\(Treap\)已经很难了,学习了\(Splay\),我才知道,没有最难,只有更难.(强烈建议先去学一学\(Treap\)再来看这篇博客) 简介 \(Splay\)是平衡树中的一种,除 ...
- Lct浅谈
Lct浅谈 1.对lct的认识 首先要知道$lct$是什么.$lct$的全称为$link-cut-tree$.通过全称可以看出,这个数据结构是维护树上的问题,并且是可以支持连边断边操作.$lct$ ...
- 浅谈 Fragment 生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...
- 浅谈 LayoutInflater
浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...
- 浅谈Java的throw与throws
转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...
- 浅谈SQL注入风险 - 一个Login拿下Server
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...
- 浅谈WebService的版本兼容性设计
在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...
随机推荐
- bzoj 1087 状压dp
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4130 Solved: 2390[Submit][ ...
- centos7 rabbitmq 安装
http://www.rabbitmq.com/install-rpm.html Overview rabbitmq-server is included in Fedora. However, th ...
- Windows 系统cmd设置添加静态路由方式
电脑上添加静态路由,cmd设置路由 方法/步骤 1.首先在“运行”窗口输入cmd(按WIN+R打开运行窗口),然后回车进入命令行,输入 route add 10.253.251.0 mask ...
- Highcharts 测量图;Highcharts 圆形进度条式测量图;Highcharts 时钟;Highcharts 双轴车速表;Highcharts 音量表(VU Meter)
Highcharts 测量图 配置 chart.type 配置 配置 chart 的 type 为 'gauge' .chart.type 描述了图表类型.默认值为 "line". ...
- hdu 6053 TrickGCD(筛法+容斥)
TrickGCD Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total ...
- CMDB Autoclient思路分析
1.start.py里的script.run():执行run函数--> 2.script.py run方法--> 3.判断模式MODE(Agent/SSHSALT)-->4.执行cl ...
- LeetCode OJ:Ugly Number II(丑数II)
Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors ...
- C++11_新语法
版权声明:本文为博主原创文章,未经博主允许不得转载. 本节主要介绍C++的新特性,对于C++的基础语法不再讲解.由于编译器的不同.在某些地方可能有些差异,但是无太大影响. 讲解本节知识之前先确认你的C ...
- Java -- 使用阻塞队列(BlockingQueue)控制线程通信
BlockingQueeu接口是Queue的子接口,但是它的主要作用并不是作为容器,而是作为线程同步的工具. 特征: 当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满,则该线程 ...
- c# 验证码图片生成类
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D ...