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的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...
随机推荐
- git日常操作
0.准备工作 0.1 git安装 http://git-scm.com/download/ 图形客户端建议使用source tree,中文界面 http://www.sourcetreeapp.c ...
- linux内核系列(二)内核数据结构之链表
双向链表 传统链表与linu内核链表的区别图: 图一 图二 从上图中看出在传统链表中各种不同链表间没有通用性,因为各个数据域不同,而在linux内核中巧妙将链表结构内嵌到数据域结构中使得不同结构之间能 ...
- 【Java基础】Integer包装类的缓冲池问题
首先看下面这个例子: public class TestNew { public static void main(String args[]){ Integer i1 = 10; //Integer ...
- POJ-2296 Map Labeler 2sat
题目链接:http://poj.org/problem?id=2296 二分+2sat,每个点的上下两个方向为2sat的两个状态. //STATUS:C++_AC_16MS_536KB #includ ...
- POJ1838
poj 1838 这道题主要是对并查集的考察,在这道题的解题过程中主要用到的算法就是并查集中的最基本的makeSet,findSet,unionSet 即前篇文章中所提到的: makeSet(Elem ...
- 小波变换和motion信号处理(三)(转)
这篇文章算太监了,去作者blog提问去吧:http://www.kunli.info/2012/04/08/fourier-wavelet-motion-signal-3/ 从前两篇发布到现在,过去一 ...
- 解决高版本 Google Chrome 扩展程序强制停用问题 -摘自网络
1]前往这里下载你喜欢的语言的组策略模板 后缀为.adm (其他的文件自己看 https://docs.google.com/viewer?a=v&pid=sites&srcid=Y2 ...
- 【设计模式】单例设计模式的N中Java实现方法
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17359719 特点 单例模式的特点: 1.只能有一个实例: 2.必须自己创建自己的一个实例 ...
- 使用Mybatis-Generator自动生成Dao、Model、Mapping相关文件
最近一直在学习SSM框架,今天遇到一个关于MyBatis生成的问题,记录一下. http://blog.csdn.net/zhshulin/article/details/37956105 我是根据这 ...
- Java通过JDBC连接Oracle之后查询结果和在sqlplus查询结果不一样
问题描述: 在sqlplus 下 orcl数据库中创建一张表后,使用insert语句插入几条数据 然后用java查询数据,发现在终端中输出的结果和在sqlplus中查询结果不一样. 在sqlplus中 ...