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;
}
posted @ 2016-01-10 00:37  Armeria  阅读(167)  评论(0编辑  收藏  举报