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的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...
随机推荐
- Hadoop学习记录(5)|集群搭建|节点动态添加删除
集群概念 计算机集群是一种计算机系统,通过一组松散继承的计算机软件或硬件连接连接起来高度紧密地协作完成计算工作. 集群系统中的单个计算机通常称为节点,通过局域网连接. 集群特点: 1.效率高,通过多态 ...
- ffmpeg编解码音频AAC
本次项目的需求:手机端和PC端共享同一个音视频网络源. 所以编解码需要满足手机上编码和解码原来PC端的音视频流. 这里先封装安卓手机端音频的编解码. 编译工作依然是在linux下 ubuntu 12. ...
- 跟我一起写Makefile:MakeFile介绍
makefile 介绍 make命令执行时,需要一个 makefile 文件,以告诉make命令如何去编译和链接程序. 首先,我们用一个示例来说明makefile的书写规则.以便给大家一个感性认识.这 ...
- java request判断微信客户端访问
微信客户端访问时候user-agent信息如下: Mozilla/5.0 (Linux; Android 5.0.1; M040 Build/LRX22C) AppleWebKit/537.36 (K ...
- 最新版postgresql+pgboucer安装
安装postgresql: wget https://pgbouncer.github.io/downloads/files/1.7.2/pgbouncer-1.7.2.tar.gz wget htt ...
- 史上最全的ASP.NET MVC路由配置,以后RouteConfig再弄不懂神仙都难救你啦~
继续延续坑爹标题系列.其实只是把apress.pro.asp.net.mvc.4.framework里的CHAPTER 13翻译过来罢了,当做自己总结吧.内容看看就好,排版就不要吐槽了,反正我知道你也 ...
- Lucene子项目------------------Solr遇到的问题
SolrCore Initialization Failures paper: org.apache.solr.common.SolrException:org.apache.solr.common. ...
- Log4E
工具地址:http://marketplace.eclipse.org/content/log4e Log4E插件能够帮助你在Java项目中轻松地创建记录器.它可以在以下几个任务中提供帮助:记录器声明 ...
- Visual C++ 2012/2013的内存溢出检測工具
在过去,每次编写C/C++程序的时候,VLD差点儿是我的标配.有了它,就能够放心地敲代码,随时发现内存溢出. VLD最高可支持到Visual Studio 2012.不知道以后会不会支持Visual ...
- 【转】C++中多重继承的二义性及解决办法
转自:http://www.cnblogs.com/lintong/archive/2012/07/28/2613002.html 1. 什么是多重继承的二义性 class A{ public: vo ...