Splaytree
伸展树是一种平横二叉树, 支持查找,插入之类的二叉树具有的功能,还独自具有树的合并和分离(合并是由条件的:要求一棵树的所有值小于另一棵树)。若有了其他平衡树的经验,写一个splay tree应该不难,但不知道后期扩展的时候的可扩性如何。
代码还是比较好些的,我自己写的也比较挫,你后做题的过程中慢慢精益求精吧。像所有人说的一样,伸展树最重要的,最核心的就是那个splay(x)操作,而且操作比较易懂,通过若干次splay(x)操作将x移到根的位置去;下面是splay的情况,和红黑树类似。
伸展操作Splay(x,S) 情况1
Zig或Zag操作:
节点x的父节点y是根节点。
即通常所说的左旋和右旋。
伸展操作Splay(x,S) 情况2
Zig-Zig或Zag-Zag操作:
节点x的父节点y不是根节点,且x与y同时是各自父节点的左孩子或者同时是各自父节点的右孩子。
伸展操作Splay(x,S) 情况3
Zig-Zag或Zag-Zig操作:
节点x的父节点y不是根节点,x与y中一个是其父节点的左孩子而另一个是其父节点的右孩子。
只要相应的将这三种情况写出来就好了。例题可用http://www.zybbs.org/JudgeOnline/problem.php?id=1588营业额统计
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespacestd;
#define INF 210000000
#define maxn 1000000
structsplayTreeNode{
int data;
splayTreeNode* l,* r,* p;
void init(int x, splayTreeNode* sl, splayTreeNode* sr,splayTreeNode* fa){
data = x, l = sl, r = sr, p = fa;
}
};
structsplayTree{
splayTreeNode* root;
splayTreeNode* link;
int ad;
splayTree(){
root = NULL;
link = newsplayTreeNode[maxn];
ad = 0;
}
~splayTree() { delete[] link;}
void rotateRight(splayTreeNode*&rt){
splayTreeNode* temp = rt->l;
rt->l = temp->r;
if(temp->r != NULL)temp->r->p = rt;
temp->r = rt;
temp->p = rt->p;
rt->p = temp;
rt = temp;
}
void rotateLeft(splayTreeNode*&rt){
splayTreeNode* temp = rt->r;
rt->r = temp->l;
if(temp->l !=NULL)temp->l->p = rt;
temp->l = rt;
temp->p = rt->p;
rt->p = temp;
rt = temp;
}
void splay(splayTreeNode*x){
if(x == root) return;
if(root->l == x ||root->r == x){
if(root->l == x)rotateRight(root);
else rotateLeft(root);
return;
}
splayTreeNode* y,* z;
y = x->p;
z = y->p;
if((z->l == y&& y->l == x) ||(z->r == y &&y->r == x)){
if((z->l ==y)){
if(z == root)rotateRight(root);
else{
if(z->p->l == z)rotateRight(z->p->l);
elserotateRight(z->p->r);
}
if(y == root)rotateRight(root);
else{
if(y->p->l == y)rotateRight(y->p->l);
elserotateRight(y->p->r);
}
}
else{
if(z == root)rotateLeft(root);
else{
if(z->p->l == z)rotateLeft(z->p->l);
elserotateLeft(z->p->r);
}
if(y == root)rotateLeft(root);
else{
if(y->p->l == y)rotateLeft(y->p->l);
elserotateLeft(y->p->r);
}
}
}
else{
if(z->l ==y){
if(y->p->l == y)rotateLeft(y->p->l);
elserotateLeft(y->p->r);
if(z == root)rotateRight(root);
else{
if(z->p->l == z)rotateRight(z->p->l);
elserotateRight(z->p->r);
}
}
else{
if(y->p->l == y)rotateRight(y->p->l);
elserotateRight(y->p->r);
if(z == root)rotateLeft(root);
else{
if(z->p->l == z)rotateLeft(z->p->l);
elserotateLeft(z->p->r);
}
}
}
splay(x);
}
void insert(int x, splayTreeNode* &rt,splayTreeNode* rf){
if(rt == NULL){
rt = &link[ad ++];
rt->init(x, NULL, NULL, rf);
splay(rt);
return;
}
if(x <rt->data) insert(x, rt->l,rt);
else insert(x,rt->r, rt);
}
bool find(int x){
for(splayTreeNode* tp = root; tp !=NULL;){
if(tp->data ==x){
splay(tp);
return 1;
}
if(x >tp->data) tp = tp->r;
else tp =tp->l;
}
return 0;
}
void remove(int x){
splayTreeNode* tp = root,* fp = root, * *temp;
for(; tp->data != x;fp = tp){
if(x <tp->data) tp = tp->l;
else tp =tp->r;
}
if(tp == NULL) return;
if(tp->l == NULL ||tp->r == NULL){
if(tp->l != NULL)temp = &(tp->l);
else temp =&(tp->r);
if(tp == fp->l)fp->l = *temp;
else fp->r =*temp;
(*temp)->p = fp;
splay(fp);
}
else{
fp = tp->l;
while(fp->r !=NULL){
fp = fp->r;
}
if(fp ==tp->l){
tp->l = fp->l;
}
else{
fp->p->r =fp->l;
fp->r->p =fp->p;
tp->data = fp->data;
}
splay(tp);
}
}
void clear(){
root = NULL;
}
int small(){
if(root == NULL ||root->l == NULL) return INF;
splayTreeNode* tp = root->l;
while(tp->r != NULL)tp = tp->r;
returntp->data;
}
int big(){
if(root == NULL ||root->r == NULL) return INF;
splayTreeNode* tp = root->r;
while(tp->l != NULL)tp = tp->l;
returntp->data;
}
};
int main(){
int n, x, sum;
while(~scanf("%d %d", &n,&sum)){
splayTree spl;
spl.insert(sum, spl.root, NULL);
for(int i = 1; i < n; ++i){
if(!(~scanf("%d", &x))) x =0;
if(spl.find(x)) continue;
spl.insert(x, spl.root, NULL);
int l = abs(x - spl.small()), r =abs(spl.big() - x);
sum += l < r ? l : r;
}
printf("%d\n", sum);
}
return 0;
}