伸展树 Splay 模板
学习Splay的时候参考了很多不同的资料,然而参考资料太杂的后果就是模板调出来一直都有问题,尤其是最后发现网上找的各种资料均有不同程度的错误。
好在啃了几天之后终于算是啃下来了。
Splay也算是平衡树的一种,但是跟AVL树、SBT不同的是,Splay并不是一直保持严格的平衡,因此在速度上可能要慢一些,但是统计学上仍能保证Splay具有O(logn)的均摊复杂度。
Splay原生不需要附加任何空间,它的先天优势是其特有的Splay操作可以非常灵活地改变整棵树的结构形态,完成一般线段树、平衡树做不到的任务。
- 基本操作-左右旋
Splay的基本操作与其他平衡树相似,都是进行结点的左右旋转。与之前写的SBT相比,Splay除了左右儿子域以外还需要一个father域,这个是因为下面的Splay操作需要用到父节点来判断当前的形态。
- 核心操作-splay
Splay(x,y)的作用是将当前点x旋转到y的子结点上,一般写y=0时则将x旋转到整棵树的根。这个操作在splay的所有函数中基本上最后都要加上,简单的理解就是将常用的结点尽可能地上移到深度较浅的地方,据统计若去掉函数最后对操作结点的splay,则整个程序将会慢上数倍。
splay基本的想法是根据当前结点父节点形态的不同,分成四种情况,逐步将结点旋转到根上。
- 进阶操作
插入、查找值、查找第k个等等...基本与普通的二叉查找树相似,但是记得在最后要加上splay,将使用过的结点旋转到根。
特殊的删除操作:
splay本身是一棵二叉搜索树,可以进行一般的删除操作。另外,二叉搜索树的性质配合splay的操作可以做到O(logn)动态删除一整个区间的结点,而一般的平衡树则只能一个一个删除。
例如:删除大于l且小于r的数,先将序号小于l的最大结点伸展到根,序号大于r的最小的结点伸展到根的右子树,则此时,r的后继结点的左子树中就存放着从l到r的所有结点,此时只要把这棵子树整个断开即可。
............
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : Splay Tree
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; #define MAXN 100000 int sons[MAXN][];
int father[MAXN],size[MAXN],data[MAXN];
int spt=,spttail=; void rotate(int x,int w) //rotate(node,0/1)
{
int y=father[x];
sons[y][-w]=sons[x][w];
if (sons[x][w]) father[sons[x][w]]=y; father[x]=father[y];
if (father[y])
if (y==sons[father[y]][]) sons[father[y]][]=x;
else sons[father[y]][]=x; sons[x][w]=y;
father[y]=x; size[x]=size[y];
size[y]=size[sons[y][]]+size[sons[y][]]+;
} void splay(int x,int y) //splay(node,position)
{
if (!x) return ;
while(father[x]!=y)
{
if (father[father[x]]==y)
if (x==sons[father[x]][]) rotate(x,);
else rotate(x,);
else
if (father[x]==sons[father[father[x]]][])
if (x==sons[father[x]][])
{
rotate(father[x],);
rotate(x,);
} else
{
rotate(x,);
rotate(x,);
}
else
if (x==sons[father[x]][])
{
rotate(father[x],);
rotate(x,);
} else
{
rotate(x,);
rotate(x,);
}
}
if (!y) spt=x;
} void search(int x,int w)
{
while(data[x]!=w)
{
if (w<data[x])
{
if (sons[x][]) x=sons[x][];
else break;
} else if (w>data[x])
{
if (sons[x][]) x=sons[x][];
else break;
}
}
splay(x,);
} void insert(int w) //insert(value)
{
spttail++;
data[spttail]=w;
size[spttail]=;
sons[spttail][]=;
sons[spttail][]=;
if (!spt)
{
father[spttail]=;
spt=spttail;
} else
{
int x=spt;
while()
{
size[x]++;
if (w<data[x])
if (sons[x][]) x=sons[x][];
else break;
else
if (sons[x][]) x=sons[x][];
else break;
}
father[spttail]=x;
if (w<data[x]) sons[x][]=spttail;
else sons[x][]=spttail;
splay(spttail,);
}
} void select(int x,int v) //select(root,k)
{
while(v!=size[sons[x][]]+)
{
if (v<=size[sons[x][]]) x=sons[x][];
else
{
v-=size[sons[x][]]+;
x=sons[x][];
}
}
splay(x,);
} int succ(int t)
{
t=sons[t][];
while(sons[t][]) t=sons[t][];
splay(t,);
return t;
} void del(int x) //del(number)
{
splay(x,); int y=sons[x][];
while(!sons[y][])
{
y=sons[y][];
} int z=sons[x][];
while(!sons[z][])
{
z=sons[z][];
} if (y+z==)
{
spt=;
spttail=;
return ;
} if (y)
{
splay(y,);
size[y]--;
}
if (z)
{
splay(z,y);
sons[z][]=;
size[z]--;
}
} int rank(int v) //rank(value)
{
search(spt,v);
return size[sons[spt][]]+;
} int main()
{
memset(father,,sizeof(father));
memset(size,,sizeof(size));
memset(sons,,sizeof(sons));
memset(data,,sizeof(data));
spt=;
spttail=; return ;
}
伸展树 Splay 模板的更多相关文章
- 树-伸展树(Splay Tree)
伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...
- 纸上谈兵: 伸展树 (splay tree)[转]
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每 ...
- K:伸展树(splay tree)
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...
- 高级搜索树-伸展树(Splay Tree)
目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...
- 伸展树Splay【非指针版】
·伸展树有以下基本操作(基于一道强大模板题:codevs维护队列): a[]读入的数组;id[]表示当前数组中的元素在树中节点的临时标号;fa[]当前节点的父节点的编号;c[][]类似于Trie,就是 ...
- POJ 3580 - SuperMemo - [伸展树splay]
题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in ...
- [数据结构]伸展树(Splay)
#0.0 写在前面 Splay(伸展树)是较为重要的一种平衡树,理解起来也依旧很容易,但是细节是真的多QnQ,学一次忘一次,还是得用博客加深一下理解( #1.0 Splay! #1.1 基本构架 Sp ...
- 伸展树Splay
新学的,其实吧,就那么回事.... 看了几天,splay处理序列问题,真的非常厉害,翻转,插入,删除,线段树实现不了的功能,splay用起来很方便. POJ 3580 SuperMemo 这题基本就是 ...
- 【BBST 之伸展树 (Splay Tree)】
最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...
随机推荐
- hdu_3001_Travelling(状压DP)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:给你N个点,M条边,每个点最多走两次,问走完N个点最短的路程为多少. 题解:注意这题有重边 ...
- jq插件开发总结
http://www.cnblogs.com/silverLee/archive/2009/12/22/1629925.html jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQue ...
- flowers
问题大全 Do you like flowers?(Why?) What flowers do you like?(why?) What is your favorite flower? Are fl ...
- perl的USE和require
来源: http://www.cnblogs.com/itech/archive/2010/11/22/1884345.html 相同: 都可以用来引用module(.PM). 不同: 1) 区别在于 ...
- redhat 安装GCC-4.8.3
1.下载gcc-4.8.3安装包 gcc各版本浏览地址:http://ftp.gnu.org/gnu/gcc/ yum install gccyum install gcc-c++ 2.将gcc-4. ...
- getopt(分析命令行参数)
ref:http://vopit.blog.51cto.com/2400931/440453 相关函数表头文件 #include<unistd.h>定义函数 ...
- How To Add Swap on Ubuntu 14.04
https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04 How To Add Swap on ...
- OpenGL红宝书例3.1 -- glBufferSubData使用
代码实现 1.1 C++部分 GLFWwindow *window; GLuint shader_program; GLuint VAO; void init() { static const GLf ...
- oracle-查询执行速度慢的sql
Oracle 查询每天执行慢的SQL 2014-12-11 18:00:04 分类: Oracle 链接:http://blog.itpub.net/28602568/viewspace-136484 ...
- Loadrunner之文件的上传(八)
老猪提供: https://mp.weixin.qq.com/s?__biz=MzIwOTMzNDEwNw==&mid=100000013&idx=1&sn=624f5bc74 ...