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的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...
随机推荐
- Android强制设置横屏或竖屏
全屏 在Activity的onCreate方法中的setContentView(myview)调用之前添加下面代码 requestWindowFeature(Window.FEATURE_NO_TIT ...
- HDOJ-ACM1071(JAVA) 定积分
这道题做起来有点无奈,定积分已经忘得差不多了~还可恶的去搜索了抛物线的解析式的求法~哈哈 不过求出来的结果不对...等有时间再去研究这个数学问题吧 - - 以下是JAVA实现: import java ...
- sql中用逗号拼接字符串
MSSQL中可以用STUFF函数拼接成字符串. 如: SELECT FieldSomeElse, ( SELECT STUFF(( SELECT ',' + LinkField FROM Detail ...
- hdoj 1231 最大连续子序列
最大连续子序列 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- PHP使用IP地址连接MySQL数据库
我们通常测试的时候都是用mysql_connect("localhost","usrname","password");的方式来连接MySQ ...
- jQuery无缝间歇向上滚动
http://www.jiangweishan.com/article/jQuery-scroll-up.html
- 关于JAVA中URL传递中文参数的问题
今天在调用一个接口时,需要传递一个中文参数,结果获取不到数据,原因就在于中文传参的编码问题. 问题来源:URL url= new URL("http://XXX?OrganName=司法厅& ...
- Notepad++中的颜色属性大全
Indent guideline style 缩进参考线的颜色 Brace highlight style 鼠标指针在框架左右时框架的颜色(如css中{} js中的()) Bad brace c ...
- Codeforces Round #382 (Div. 2)E. Ostap and Tree
E. Ostap and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...
- IOS GCD 使用 (二)
上一节,主要介绍了GCD的基本的概念,这节将用代码深入详细介绍GCD的使用. 一 使用介绍 GCD的使用主要分为三步:创建代码块;选择或创建合适的分发队列;(同步.异步方式)向分发队列提交任 ...