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的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...
随机推荐
- CMD-CMD命令之新建一个用户!
1>>>>>> 新建管理员账号: net user net user xxxxx 123 /add net localgroup administrators xx ...
- 问题-[WIN8.132位系统]安装Win8.1 遇到无法升级.NET Framework 3.5.1
问题现象:安装Win8后都遇到了无法升级.NET Framework 3.5.1的问题,在线升级会遇到错误0x800F0906.这使得91手机助手等很多软件无法运行,更郁闷的是,网上几乎所有的解决办法 ...
- hdoj 4183 Pahom on Water
Pahom on Water Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- hdoj 2803 The MAX【简单规律题】
The MAX Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- AS3 IOC框架Spring Actionscript 的使用总结
Spring Actionscript 是众多围绕依赖注入提供解决方案的Flex控制反转框架之一 AS3 下经典的IOC框架有Spring ActionScript.Parsley.Flicc和Swi ...
- [转载](iPhone开发)Bundle Display Name 改为中文。ap
原文地址:(iPhone开发)Bundle Display Name 改为中文.app显示为中文作者:小新 要先在info的Localizations加入Chinese(zh-Hant) 再進到inf ...
- 【转】C++ 类中的static,const,及引用类型的初始化
文档主要来自:http://blog.csdn.net/yjkwf/article/details/6067267 1. static类型 用static可以为类类型的所有对象所共有,像是全局对象,但 ...
- 跟我一起学extjs5(05--主界面上增加顶部和底部区域)
跟我一起学extjs5(05--主界面上增加顶部和底部区域) 这一节为主界面加一个顶部区域和底部区域. 一个管理系统的界面能够粗分为顶部标题部分.中间数据展示和处理的部分.底部备注和状 ...
- POJ 3670 , 3671 LIS
题意:两题意思差不多,都是给你一个序列,然后求最少需要改变多少个数字,使得成为一个最长不升,或者最长不降子序列. 当然3671是只能升序,所以更简单一点. 然后就没有什么了,用二分的方法求LIS即可. ...
- 深入理解JavaScript系列+ 深入理解javascript之执行上下文
http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html http://blog.csdn.net/hi_kevin/article/d ...