花了一天钻研了splay,然后发现splay没我想象的那么难……以前都是写SBT来着…… 但是splay的速度确实没那么快,但是真的挺好写的~
我写的版本测了这题以后又用了一下别人的splay,发现通过这题大多数splay在750ms上下,我是688ms,说明还算是不错的啦~啦啦啦~
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
struct node
{
int count, key;
node *left_son, *right_son, *father;
node():count(0), key(0), left_son(NULL), right_son(NULL), father(NULL){}
node(int tmp, node *tmp_node):count(1), key(tmp), left_son(NULL), right_son(NULL), father(tmp_node){}
}*proot = new node;
//返回a指针的儿子数量
#define RNC(a) ((a)==NULL?0:a->count)
void pg(node &t)
{
cout<<"key = "<<t.key<<" count = "<< t.count <<" " << endl;
if (t.father != NULL) cout <<"fa ="<<t.father -> key<<" ";
else cout<<"no father ";
if (t.left_son != NULL) cout<<"L = "<<t.left_son -> key<<" ";
else cout<<"no L ";
if (t.right_son != NULL) cout<<"R = "<<t.right_son -> key<<" ";
else cout<<"no R ";
cout<<endl<<endl;
if (t.left_son != NULL) pg(*t.left_son);
if (t.right_son != NULL) pg(*t.right_son);
}
void zig(node &x) //右旋
{
node *y =x.father;
x.count = RNC(x.left_son) + RNC(x.right_son) + 1 + RNC(y -> right_son) + 1;
y -> count = x.count - 1 - RNC(x.left_son);
/*重新出x节点,和y节点的儿子数量*/
y -> left_son = x.right_son;
if (x.right_son != NULL) x.right_son -> father = y;
x.father = y -> father;
if (y -> father != NULL)
if (y -> father -> left_son == y) y -> father -> left_son = &x;
else y -> father -> right_son = &x;
y -> father = &x;
x.right_son = y;
}
void zag(node &x)
{
node *y = x.father;
x.count = RNC(x.right_son) + RNC(x.left_son) + 1 + RNC(y -> left_son) + 1;
y -> count = x.count - 1 - RNC(x.right_son);
y -> right_son = x.left_son;
if (x.left_son != NULL) x.left_son -> father = y;
x.father = y -> father;
if (y -> father != NULL)
if (y -> father -> left_son == y) y -> father -> left_son = &x;
else y -> father -> right_son = &x;
y -> father = &x;
x.left_son = y;
}
void splay(node &x)
{
node *y;
while ((y = x.father) != NULL)
{
if (y -> father == NULL)
{
if (&x == y -> left_son) zig(x);
else zag(x);
break;
}
if (&x == y -> left_son)
{
if (y == y -> father -> left_son)
{
zig(*y);
zig(x);
}else{
zig(x);
zag(x);
}
}else
{
if (y == y -> father -> right_son)
{
zag(*y);
zag(x);
}else{
zag(x);
zig(x);
}
}
}
proot = &x;
}
node* search_node(int valve, node &t = *proot)//搜索valve从t节点开始搜索,找不到,就返回最后找到的位置
{
node *x = &t;
while (x -> key != valve)
{
if (valve <= x -> key)
{
if (x -> left_son == NULL) break;
x = x -> left_son;
}else{
if (x -> right_son == NULL) break;
x = x -> right_son;
}
}
return x;
}
void insert_node(int valve)
{
if (!proot -> count)
{
proot -> count = 1;
proot -> key = valve;
return;
}
node *pos(search_node(valve, *proot));
if (valve <= pos -> key)
{
pos -> left_son = new node(valve, pos);
splay(*(pos -> left_son));
}else
{
pos -> right_son = new node(valve, pos);
splay(*(pos -> right_son));
}
}
/*
* 寻找从x节点为根的极大值
* 直接去search_node去找一个极大值,一定找不到,最后找到的那个点,就是最大值
* 把最大值调整到他们通过父亲节点所能追溯到的最早的节点
* PS:为何不直接调整到根?为何总是要调整? 其实都是代码省事的 > 真正的效率……
*/
node* exterme_max(node &x) //找从x节点为根的最大值
{
node *pos = search_node(0x7fffffff, x);
splay(*pos);
return pos;
}
node* exterme_min(node &x)
{
node *pos = search_node(-0x7fffffff, x);
splay(*pos);
return pos;
}
/*
* 从整棵树中删除值为valve的节点
* 找到valve,旋转到根
* 如果只有一个节点,那么要特殊判断一下
* 如果根没有左儿子,那么直接让右儿子当根
* 如果有左儿子,那么找到左儿子的最大值,旋转到左儿子的位置上
* 此时,[根的左儿子]一定没有[右儿子](他最大,当然没有右儿子)
* 把[根的右儿子],并到[根的左儿子]的右儿子上
*/
bool delete_node(int valve)
{
node *pos = search_node(valve, *proot);
if (pos -> key != valve) return false;//根本没有valve 删除失败
splay(*pos);
if (proot -> left_son == NULL)
{
proot = pos -> right_son;
delete pos;
}else{
proot -> left_son -> father = NULL;
proot = exterme_max(*(pos -> left_son));
delete pos;
}
}
/*找前驱
* 先找到valve,把valve旋转到根节点
* 这个时候,根左儿子的最大值,和右儿子最小值,就是valve的前驱。 后继同理
* PS:返回下标,有利于判断是否不存在前驱后继
*/
node* find_node_pre(int valve)
{
node *pos = search_node(valve, *proot);
splay(*pos);
if (proot -> left_son == NULL) return NULL;
return exterme_max(*(proot -> left_son));
}
//找后继
node* find_node_next(int valve)
{
node *pos = search_node(valve, *proot);
splay(*pos);
if (proot -> right_son == NULL) return NULL;
return exterme_min(*(proot -> right_son));
}
//查询valve的排名1 ****因为本题没有设计查排名操作,所以查排名操作没有验证对错
/*
* 查询valve排名,和其他二叉树方法一样
*/
int rank_node(int valve)
{
int ans = 0;
node *x = proot;
while (x -> key != valve)
{
if (valve <= x ->key)
{
if (x -> left_son == NULL) return -1;
x = x -> left_son;
}else
{
if (x -> right_son == NULL) return -1;
ans += 1 + RNC(x -> left_son);
x = x-> right_son;
}
}
ans += RNC(x -> left_son);
return ans;
}
//查排名操作2
int find_rank_node(int valve)
{
search_node(valve, *proot);
return RNC(proot -> left_son) + 1;
}
int n, tmp, ans;
int main()
{
ios::sync_with_stdio(false);
cin >> n;
cin >> tmp;
--n;
ans = tmp;
insert_node(tmp);
while (n--)
{
if ( (cin >> tmp) == NULL) tmp =0;
if (search_node(tmp) -> key == tmp) continue;
insert_node(tmp);
node *pre_node = find_node_pre(tmp);
node *next_node = find_node_next(tmp);
int a, b;
if (pre_node == NULL) a = 0x7fffffff;
else a = pre_node -> key;
if (next_node == NULL) b = 0x7fffffff;
else b = next_node -> key;
a = abs(a - tmp);
b = abs(b - tmp);
ans += min(a, b);
}
cout << ans << endl;
return 0;
}
花了时间研究zkw splay tree,也就是自顶向下维护的神奇splay,各种快!而且程序更短功能更好用!!!决定用这个程序当模板了!
强烈推荐,速度快了6倍!
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxint = 0x7fffffff;
struct node
{
int key;
int size;
node *c[2];
node(): key(0), size(0){c[0] = c[1] = this;}
node (int KEY_, node *c0, node *c1):
key(KEY_){c[0] = c0, c[1] = c1;}
node* rz(){return size = c[0] -> size + c[1] -> size + 1, this;}
} Tnull, *null = &Tnull;
struct splay
{
node *root;
splay()
{
root = (new node(*null)) -> rz();
root -> key = maxint;
}
void zig(bool d)
{
node *t = root -> c[d];
root -> c[d] = null -> c[d];
null -> c[d] = root;
root = t;
}
void zigzig(bool d)
{
node *t = root -> c[d] -> c[d];
root -> c[d] -> c[d] = null -> c[d];
null -> c[d] = root -> c[d];
root -> c[d] = null -> c[d] -> c[!d];
null -> c[d] -> c[!d] = root -> rz();
root = t;
}
void finish(bool d)
{
node *t = null -> c[d], *p = root -> c[!d];
while (t != null)
{
t = null -> c[d] -> c[d];
null -> c[d] -> c[d] = p;
p = null -> c[d] -> rz();
null -> c[d] = t;
}
root -> c[!d] = p;
}
void select(int k)
{
int t;
while (1)
{
bool d = k > (t = root -> c[0] -> size);
if (k == t || root -> c[d] == null) break;
if (d) k -= t + 1;
bool dd = k > (t = root -> c[d] -> c[0] -> size);
if (k == t || root -> c[d] -> c[dd] == null){zig(d); break;}
if (dd) k -= t + 1;
d != dd ? zig(d), zig(dd) : zigzig(d);
}
finish(0), finish(1);
root -> rz();
}
void search(int x)
{
while (1)
{
bool d = x > root -> key;
if (root -> c[d] == null) break;
bool dd = x > root -> c[d] -> key;
if (root -> c[d] -> c[dd] == null){zig(d);break;}
d != dd ? zig(d), zig(dd) : zigzig(d);
}
finish(0); finish(1);
root -> rz();
if (x > root -> key) select(root -> c[0] -> size + 1);
}
void ins(int x)
{
search(x);
node *oldroot = root;
root = new node(x, oldroot -> c[0], oldroot);
oldroot -> c[0] = null;
oldroot -> rz();
root -> rz();
}
void del(int x)
{
search(x);
node *oldroot = root;
root = root -> c[1];
select(0);
root -> c[0] = oldroot -> c[0];
root -> rz();
delete oldroot;
}
int sel(int k){return select(k - 1), root -> key;}
int ran(int x){return search(x), root -> c[0] -> size + 1;}
}sp;
int n, tmp, ans;
int main()
{
ios::sync_with_stdio(false);
cin >> n;
cin >> tmp;
--n;
ans = tmp;
sp.ins(tmp);
while (n--)
{
if ( (cin >> tmp) == NULL) tmp =0;
sp.ins(tmp);
int rank = sp.ran(tmp);
int a = maxint, b = maxint;
int t1 = maxint/2, t2 = maxint;
if (rank != 1)
{
t1 = a = sp.sel(rank - 1);
a = abs(a - tmp);
}
t2 = b = sp.sel(rank + 1);
// cout<<rank<<" "<<t1<<" "<<t2<<endl;
b = abs(b - tmp);
ans += min(a, b);
}
cout << ans << endl;
return 0;
}