BZOJ 1588 - 二叉搜索树
本题是Treap/Splay的模板题了… 也可以用set或者双向链表实现。
(其实这题是在NOIP2012 Day1 T3的一部分啊。。
由于我懒,所以只码了Treap。还有很多模板题,先把这几种数据结构刷熟再说。
平衡树上找一个元素的前缀/后缀只要脑补一下,左左右右地走一走就行了。
第一次码,出现了不少问题,也从各种千奇百怪的模板中学到了不少。详见代码注释。
// BZOJ 1588
#include <cstdio>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define rep(i,a,b) for (int i=a; i<=b; i++)
#define read(x) scanf("%d", &x)
const int INF=0x3f3f3f3f;
struct Node {
Node *son[2];
int p, v;
Node() {}
Node(int v):v(v) { son[1]=son[0]=NULL, p=rand(); }
int cmp(int x) const {
if (x==v) return -1;
return x<v ? 0 : 1;
}
};
void rotate(Node *&o, int d) { // 注意rotate和insert的Node都是引用+指针!
Node *k = o->son[d^1];
o->son[d^1] = k->son[d];
k->son[d] = o;
o=k;
}
void insert(Node *&o, int x) {
if (o==NULL) o = new Node(x);
else {
int d = o->cmp(x);
if (d==-1) return;
insert(o->son[d], x);
if (o->son[d]->p > o->p) rotate(o, d^1);
}
}
void query_before(Node *o, int x, int &ret) {
if (o==NULL) return;
int v=o->v;
if (v==x) { ret=v; return; }
if (v<=x) {
ret=v;
query_before(o->son[1], x, ret);
}
else query_before(o->son[0], x, ret);
}
void query_after(Node *o, int x, int &ret) {
if (o==NULL) return;
int v=o->v;
if (v==x) { ret=v; return; }
if (v>=x) {
ret=v;
query_after(o->son[0], x, ret);
}
else query_after(o->son[1], x, ret);
}
int main()
{
int ans=0, n, x, l, r;
read(n); read(x);
Node *root=new Node(x); // 以第一个数据作为根节点建树
ans+=x;
rep(i,2,n) {
if (scanf("%d", &x)==EOF) x=0; // 用于解决本题的一些奇怪的数据错误
l=r=INF;
query_before(root, x, l);
query_after(root, x, r);
ans+=(min(abs(x-l), abs(x-r)));
insert(root, x);
}
printf("%d\n", ans);
return 0;
}