splay tree
Posted Code--Dream
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了splay tree相关的知识,希望对你有一定的参考价值。
类别:二叉排序树 空间效率:O(n)
时间效率:O(log n)内完成插入、查找、删除操作 创造者:Daniel Sleator和Robert Tarjan 优点:每次查询会调整树的结构,使被查询频率高的条目更靠近树根。
注:所有图片来自wiki。
http://blog.csdn.net/cyberzhg/article/details/8058208
Tree Rotation
树的旋转是splay的基础,对于二叉查找树来说,树的旋转不破坏查找树的结构。
Splaying
Splaying是Splay Tree中的基本操作,为了让被查询的条目更接近树根,Splay Tree使用了树的旋转操作,同时保证二叉排序树的性质不变。 Splaying的操作受以下三种因素影响:
- 节点x是父节点p的左孩子还是右孩子
- 节点p是不是根节点,如果不是
- 节点p是父节点g的左孩子还是右孩子
Zig Step
当p为根节点时,进行zip step操作。 当x是p的左孩子时,对x右旋; 当x是p的右孩子时,对x左旋。
Zig-Zig Step
当p不是根节点,且x和p同为左孩子或右孩子时进行Zig-Zig操作。 当x和p同为左孩子时,依次将p和x右旋; 当x和p同为右孩子时,依次将p和x左旋。
Zig-Zag Step
当p不是根节点,且x和p不同为左孩子或右孩子时,进行Zig-Zag操作。 当p为左孩子,x为右孩子时,将x左旋后再右旋。 当p为右孩子,x为左孩子时,将x右旋后再左旋。
应用
Splay Tree可以方便的解决一些区间问题,根据不同形状二叉树先序遍历结果不变的特性,可以将区间按顺序建二叉查找树。 每次自下而上的一套splay都可以将x移动到根节点的位置,利用这个特性,可以方便的利用Lazy的思想进行区间操作。 对于每个节点记录size,代表子树中节点的数目,这样就可以很方便地查找区间中的第k小或第k大元素。 对于一段要处理的区间[x, y],首先splay x-1到root,再splay y+1到root的右孩子,这时root的右孩子的左孩子对应子树就是整个区间。 这样,大部分区间问题都可以很方便的解决, 操作同样也适用于一个或多个条目的添加或删除,和区间的移动。
POJ2764 Feed the dogs
http://poj.org/problem?id=2764http://blog.csdn.net/cyberzhg/article/details/8058154
区间不会重叠,所以不可能有首首相同或尾尾相同的情况,读入所有区间,按照右端由小到大排序。然后通过维护splay进行第k小元素的查询操作。
[cpp] view plain copy print ?
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- const int MAXN = 100005;
- const int MAXM = 50005;
- const int INF = 0x7FFFFFFF;
- class SplayTree
- public:
- SplayTree()
- nil = &_nil;
- _nil.value = 0;
- _nil.size = 0;
- _nil.parent = nil;
- _nil.child[LEFT] = nil;
- _nil.child[RIGHT] = nil;
- inline void clear()
- nodeNumber = 0;
- root = nil;
- insert(-INF);
- insert(INF);
- inline void insert(const int value)
- if(root == nil)
- root = newNode(nil, value);
- return;
- Node *x = root;
- while(true)
- int dir = x->value < value;
- if(x->child[dir] == nil)
- x->child[dir] = newNode(x, value);
- update(x);
- splay(x->child[dir], nil);
- return;
- else
- x = x->child[dir];
- inline void remove(const int value)
- int k = find(value);
- find(k - 1, nil);
- find(k + 1, root);
- root->child[RIGHT]->child[LEFT] = nil;
- update(root->child[RIGHT]);
- update(root);
- inline int getKth(const int k)
- find(k + 1, nil);
- return root->value;
- inline void print()
- printf("Splay Tree: \\n");
- print(root);
- printf("\\n");
- private:
- static const int LEFT = 0;
- static const int RIGHT = 1;
- struct Node
- int value, size;
- Node *parent, *child[2];
- _nil, node[MAXN];
- int nodeNumber;
- Node *root, *nil;
- inline Node *newNode(Node *parent, const int value)
- node[nodeNumber].value = value;
- node[nodeNumber].size = 1;
- node[nodeNumber].parent = parent;
- node[nodeNumber].child[LEFT] = nil;
- node[nodeNumber].child[RIGHT] = nil;
- return &node[nodeNumber++];
- inline void update(Node *x)
- if(x == nil)
- return;
- x->size = x->child[LEFT]->size + x->child[RIGHT]->size + 1;
- inline void rotate(Node *x, const int dir)
- splay tree