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的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...
随机推荐
- Linux下platform设备以及platform设备和驱动注册的先后顺序
platform是Linux系统提供的一种管理设备的手段,所有SOC系统中集成的独立的外设控制器.挂接在SOC内存空间的外设等都属Platform设备.如ARM S3C6410处理器中,把内部集成的I ...
- WordPress更新服务加快收录
WordPress更新服务的设置在后台"设置"-"撰写".更新服务下的文本框中默认为http://rpc.pingomatic.com/.该地址网站Ping-o ...
- centos "cannot open display"的问题
实用技巧:在Linux下设置xhost方法步骤 第一步:用root登陆linux,启动vnc服务: 第二步:根据vnc起来的端口,设置export DISPLAY=localhost:1(1表示vnc ...
- 【Java基础】成员变量和局部变量的区别
在类中的位置不同 成员变量:在类内部方法外部 局部变量:在方法体内部定义的或者方法的参数中定义的在内存中的位置不同 成员变量:在堆内存,有初始化值,byte,short,int,long->0, ...
- Codeforces149D - Coloring Brackets(区间DP)
题目大意 要求你对一个合法的括号序列进行染色,并且需要满足以下条件 1.要么不染色,要么染红色或者蓝色 2.对于任何一对括号,他们当中有且仅有一个被染色 3.相邻的括号不能染相同的颜色 题解 用区间d ...
- mongodb的优化
1:使用索引 ,同时对索引排序,[比如mongodb对时间做索引都用-1降序哈,这样查询最新的速度很快],注意组合索引中字段的顺序要和查询时字段的顺序一致哈, 用find().explain()检查查 ...
- 如何使用iframe实现隐藏的CSRF
1.攻击者在“页面1”中http://www.b.com/indexb.html中写下如下代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. ...
- vector中的resize与 reserve
void reserve (size_type n); reserver函数用来给vector预分配存储区大小,即capacity的值 ,但是没有给这段内存进行初始化.reserve 的参数n是推荐预 ...
- QT QSqlQuery QSqlQueryModel
SQL执行操作 QSqlQuery提供了对数据库记录的Select.Insert.Update.Delete操作. SELECT操作: QSqlQuery query; query.exec(&q ...
- C#数据库读取数据后转换为INT32后计算的小技巧
这有什么难的,不管是什么数据库, 首先分别读出userinfo中usermoney的值 存入s1,card中extramoney的值s2 读出字段数据你应该会吧! 再用userinfo中字段userm ...