Splay tree
类别:二叉排序树
时间效率:O(log n)内完成插入、查找、删除操作
伸展树的另一个好处是将最近搜索的节点放在最容易搜索的根节点的位置。在许多应用环境中,比如网络应用中,某些固定内容会被大量重复访问(比如江南style的MV)。伸展树可以让这种重复搜索以很高的效率完成。
注:所有图片来自wiki。
Tree Rotation

Splaying
- 节点x是父节点p的左孩子还是右孩子
- 节点p是不是根节点,如果不是
- 节点p是父节点g的左孩子还是右孩子
Zig Step

Zig-Zig Step

Zig-Zag Step

应用
POJ2764 Feed the dogs
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
const int MAXM = 100005;
const int INF = 0x7fffffff;
class SplayTree
{
public:
SplayTree()
{
nil.size = 0;
nil.value = INF;
nil.min = INF;
nil.lchild = &nil;
nil.rchild = &nil;
nil.parent = &nil;
}
inline void make(int array[], int n)
{
nodeNumber = 0;
int mid = (n - 1) >> 1;
root = newNode(&nil, array[mid]);
root->lchild = make(0, mid - 1, root, array);
root->rchild = make(mid + 1, n - 1, root, array);
update(root);
}
inline void ADD(int x, int y, int D)
{
find(x, &nil);
find(y + 2, root);
root->rchild->lchild->lazy += D;
}
inline void REVERSE(int x, int y)
{
find(x, &nil);
find(y + 2, root);
root->rchild->lchild->isReverse ^= true;
}
inline void REVOLVE(int x, int y, int T)
{
int len = y - x + 1;
T = ((T % len) + len) % len;
if(T)
{
find(y - T + 1, &nil);
find(y + 2, root);
SplayNode *d = root->rchild->lchild;
root->rchild->lchild = &nil;
find(x, &nil);
find(x + 1, root);
root->rchild->lchild = d;
d->parent = root->rchild;
}
}
inline void INSERT(int x, int P)
{
find(x + 1, &nil);
find(x + 2, root);
root->rchild->lchild = newNode(root->rchild, P);
}
inline void DELETE(int x)
{
find(x, &nil);
find(x + 2, root);
root->rchild->lchild = &nil;
}
inline void MIN(int x, int y)
{
find(x, &nil);
find(y + 2, root);
pushdown(root->rchild->lchild);
printf("%d\n", root->rchild->lchild->min);
}
inline void print()
{
printf("Splay Linear: \n");
print(root);
printf("\n");
}
inline void prints()
{
printf("Splay Structure: \n");
prints(root);
printf("\n");
}
private:
struct SplayNode
{
int value, size, lazy;
SplayNode *parent, *lchild, *rchild;
int min;
bool isReverse;
} nil, node[MAXN + MAXM];
int nodeNumber;
SplayNode *root;
inline SplayNode *newNode(SplayNode *parent, const int value)
{
node[nodeNumber].value = value;
node[nodeNumber].size = 1;
node[nodeNumber].lazy = 0;
node[nodeNumber].parent = parent;
node[nodeNumber].lchild = &nil;
node[nodeNumber].rchild = &nil;
node[nodeNumber].min = value;
node[nodeNumber].isReverse = false;
return &node[nodeNumber++];
}
SplayNode *make(int l, int r, SplayNode *parent, int array[])
{
if(l > r)
{
return &nil;
}
int mid = (l + r) >> 1;
SplayNode *x = newNode(parent, array[mid]);
x->lchild = make(l, mid - 1, x, array);
x->rchild = make(mid + 1, r, x, array);
update(x);
return x;
}
inline void update(SplayNode *x)
{
if(x == &nil)
{
return;
}
x->size = x->lchild->size + x->rchild->size + 1;
x->min = min(x->value, min(x->lchild->min, x->rchild->min));
}
inline void pushdown(SplayNode *x)
{
if(x == &nil)
{
return;
}
if(x->isReverse)
{
swap(x->lchild, x->rchild);
x->lchild->isReverse ^= true;
x->rchild->isReverse ^= true;
x->isReverse = false;
}
if(x->lazy)
{
x->value += x->lazy;
x->min += x->lazy;
x->lchild->lazy += x->lazy;
x->rchild->lazy += x->lazy;
x->lazy = 0;
}
}
inline void rotateLeft(SplayNode *x)
{
SplayNode *p = x->parent;
pushdown(x->lchild);
pushdown(x->rchild);
pushdown(p->lchild);
p->rchild = x->lchild;
p->rchild->parent = p;
x->lchild = p;
x->parent = p->parent;
if(p->parent->lchild == p)
{
p->parent->lchild = x;
}
else
{
p->parent->rchild = x;
}
p->parent = x;
update(p);
update(x);
if(root == p)
{
root = x;
}
}
inline void rotateRight(SplayNode *x)
{
SplayNode *p = x->parent;
pushdown(x->lchild);
pushdown(x->rchild);
pushdown(p->rchild);
p->lchild = x->rchild;
p->lchild->parent = p;
x->rchild = p;
x->parent = p->parent;
if(p->parent->lchild == p)
{
p->parent->lchild = x;
}
else
{
p->parent->rchild = x;
}
p->parent = x;
update(p);
update(x);
if(root == p)
{
root = x;
}
}
inline void splay(SplayNode *x, SplayNode *y)
{
pushdown(x);
while(x->parent != y)
{
if(x->parent->parent == y)
{
if(x->parent->lchild == x)
{
rotateRight(x);
}
else
{
rotateLeft(x);
}
}
else if(x->parent->parent->lchild == x->parent)
{
if(x->parent->lchild == x)
{
rotateRight(x->parent);
rotateRight(x);
}
else
{
rotateLeft(x);
rotateRight(x);
}
}
else
{
if(x->parent->rchild == x)
{
rotateLeft(x->parent);
rotateLeft(x);
}
else
{
rotateRight(x);
rotateLeft(x);
}
}
}
update(x);
}
inline void find(int k, SplayNode *y)
{
SplayNode *x = root;
pushdown(x);
while(k != x->lchild->size + 1)
{
if(k <= x->lchild->size)
{
x = x->lchild;
}
else
{
k -= x->lchild->size + 1;
x = x->rchild;
}
pushdown(x);
}
splay(x, y);
}
inline void print(SplayNode *x)
{
if(x == &nil)
{
return;
}
pushdown(x);
print(x->lchild);
printf("%d: %d %d %d %d\n", x->value, x->min, x->parent->value, x->lchild->value, x->rchild->value);
print(x->rchild);
}
inline void prints(SplayNode *x)
{
if(x == &nil)
{
return;
}
pushdown(x);
if(x->value == INF)
{
printf("INF : ");
}
else
{
printf("%d : ", x->value);
}
if(x->lchild == &nil)
{
printf("nil ");
}
else
{
if(x->lchild->value == INF)
{
printf("INF ");
}
else
{
printf("%d ", x->lchild->value);
}
}
if(x->rchild == &nil)
{
printf("nil\n");
}
else
{
if(x->rchild->value == INF)
{
printf("INF\n");
}
else
{
printf("%d\n", x->rchild->value);
}
}
prints(x->lchild);
prints(x->rchild);
}
} splayTree;
char buffer[128];int array[MAXN];int n, m;
int main()
{
int x, y, D, T, P;
scanf("%d", &n);
for(int i=1;i<=n;++i)
{
scanf("%d", &array[i]);
}
array[0] = INF;
array[n+1] = INF;
splayTree.make(array, n + 2);
scanf("%d", &m);
while(m--)
{
scanf("%s", buffer);
switch(buffer[0])
{
case 'A':
scanf("%d%d%d", &x, &y, &D);
splayTree.ADD(x, y, D);
break;
case 'R':
if('E' == buffer[3])
{
scanf("%d%d", &x, &y);
splayTree.REVERSE(x, y);
}
else
{
scanf("%d%d%d", &x, &y, &T);
splayTree.REVOLVE(x, y, T);
}
break;
case 'I':
scanf("%d%d", &x, &P);
splayTree.INSERT(x, P);
break;
case 'D':
scanf("%d", &x);
splayTree.DELETE(x);
break;
case 'M':
scanf("%d%d", &x, &y);
splayTree.MIN(x, y);
break;
}
}
return 0;
}
Splay tree的更多相关文章
- 纸上谈兵:伸展树(splay tree)
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每次 ...
- bzoj 3223/tyvj 1729 文艺平衡树 splay tree
原题链接:http://www.tyvj.cn/p/1729 这道题以前用c语言写的splay tree水过了.. 现在接触了c++重写一遍... 只涉及区间翻转,由于没有删除操作故不带垃圾回收,具体 ...
- 伸展树 Splay Tree
Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...
- [转] Splay Tree(伸展树)
好久没写过了,比赛的时候就调了一个小时,差点悲剧,重新复习一下,觉得这个写的很不错.转自:here Splay Tree(伸展树) 二叉查找树(Binary Search Tree)能够支持多种动态集 ...
- 树-伸展树(Splay Tree)
伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...
- HDU-3436 Queue-jumpers 树状数组 | Splay tree删除,移动
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3436 树状数组做法<猛戳> Splay tree的经典题目,有删除和移动操作.首先要离散化 ...
- HDU1890 Robotic Sort Splay tree反转,删除
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890 题目中涉及数的反转和删除操作,需要用Splay tree来实现.首先对数列排序,得到每个数在数列 ...
- POJ-3468 A Simple Problem with Integers Splay Tree区间练习
题目链接:http://poj.org/problem?id=3468 以前用线段树做过,现在用Splay Tree A了,向HH.kuangbin.cxlove大牛学习了各种Splay各种操作,,, ...
- Splay Tree的删除操作
Splay Tree的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...
随机推荐
- HW4.5
public class Solution { public static void main(String[] args) { final double POUNDS_PER_KILOGRAM = ...
- Storm与Hadoop的角色和组件比较
Storm与Hadoop的角色和组件比较 Storm 集群和 Hadoop 集群表面上看很类似.但是 Hadoop 上运行的是 MapReduce 作业,而在 Storm 上运行的是拓扑 Topolo ...
- 【转】科普Spark,Spark是什么,如何使用Spark
本博文是转自如下链接,为了方便自己查阅学习和他人交流.感谢原博主的提供! http://www.aboutyun.com/thread-6849-1-1.html http://www.aboutyu ...
- 问题-[Delphi]用LoadLibrary加载DLL时返回0的错误
问题现象:用LoadLibrary加载DLL一直返回0句柄,无法进行下一步操作,但同样的代码可以访问到别的DLL.问题处理:1.你加载的路径是不对的,一定要看好路径.2.你是在虚拟机中操作的DLL,因 ...
- usb 设备的端点 及输入输出方向
- highcharts 柱形图 饼图 加URL或Click事件
我们在做图表的时候,有时候需要在单个数据上加链接或点击事件,是在plotOptions里的events里设置的 plotOptions: { pie: { cursor: 'pointer', eve ...
- Android 各种MIME类型和文件类型的匹配表
MIME:全称Multipurpose Internet Mail Extensions,多功能Internet 邮件扩充服务.它是一种多用途网际邮件扩充协议,在1992年最早应用于电子邮件系统,但后 ...
- IOS 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: URLString'
转载自:http://i.cnblogs.com/EditPosts.aspx?postid=4012011 今天想写一个请求的天气,好的,废话不多说,先贴代码: 使用AFNetWorking 发送g ...
- ThinkPHP3.1新特性:命名范围
概述 命名范围功能,给模型操作提供了一系列的(连贯操作)封装,让你更方便的查询和操作数据.我们来具体了解下这一用法. 定义属性 要使用命名范围功能,主要涉及到模型类的_scope属性定义和scope连 ...
- Override ListView getAdapter造成的后果
近期工作中,发现了一个bug,是和ListView Adapter有关的.产生了FC,描写叙述信息大约是 "The content of the adapter has changed bu ...