题解 P6136

· · 题解

Splay

伸展树(\operatorname{Splay\ Tree}),也叫分裂树,是一种二叉排序树,它能在 \operatorname O(\log n) 内完成插入、查找和删除操作。它由丹尼尔·斯立特 Daniel Sleator 和 罗伯特·恩卓·塔扬 Robert Endre Tarjan 在1985年发明的。

在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法, 在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。伸展树应运而生。伸展树是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。

它的优势在于不需要记录用于平衡树的冗余信息。

旋转是 Splay_Tree 时间复杂度的保证,在每次操作后都尽量旋转。

以下是题目要求操作的实现。比较简单。可以略过直接看代码。

template<typename T = unsigned int>
class Balanced_Binary_Tree {
private:
    struct Point {
        T value;
        unsigned int count;
        unsigned int size;
        unsigned int daughter[2], mother;
        Point() { size = count = 0, mother = daughter[1] = daughter[0] = 0; }
        Point(T const value) {
            this->value = value,
            size = count = 1, mother = daughter[1] = daughter[0] = 0;
        }
    } tree[N + M + 1];
    unsigned int length, size, root;
    bool inline get_id(unsigned int const x) const {
        return tree[tree[x].mother].daughter[1] == x;
    }
    void const inline upto(unsigned int const x) {
        tree[x].size =
            tree[tree[x].daughter[0]].size + tree[tree[x].daughter[1]].size
            + tree[x].count;
    }
    void const inline connect
        (unsigned int const x, unsigned int const y, bool const id) {
        tree[x].mother = y, tree[y].daughter[id] = x;
    }
    void const inline rotate(unsigned int const x) {
        unsigned int const m(tree[x].mother), g(tree[m].mother);
        bool const id(get_id(x)), mid(get_id(m));
        connect(tree[x].daughter[!id], m, id), upto(m),
        connect(m, x, !id), upto(x), connect(x, g, mid);
    }
    void const inline splay(unsigned int const x, unsigned int root) {
        root = tree[root].mother;
        while (tree[x].mother not_eq root)
            if (tree[tree[x].mother].mother == root) rotate(x);
            else
                if (get_id(x) == get_id(tree[x].mother))
                    rotate(tree[x].mother), rotate(x);
                else
                    rotate(x), rotate(x);
    }
    void const inline Splay(unsigned int const x) {
        splay(x, root), root = x;
    }
public:
    Balanced_Binary_Tree() { size = length = 0; }
    void const inline Insert(T const x) {
        if (not size++) {
            tree[root = ++length] = Point(x), connect(root, 0, 0);
            return;
        }
        for (unsigned int register i(root); ++tree[i].size, true;) {
            if (tree[i].value == x)
                { ++tree[i].count, Splay(i); return; }
            else {
                bool id(tree[i].value < x);
                if (not tree[i].daughter[id]) {
                    tree[++length] = Point(x), connect(length, i , id),
                    Splay(length);
                    return;
                }
                else
                    i = tree[i].daughter[id];
            }
        }
    }
    void const inline Delete(T const x) {
        --size;
        for (
            unsigned int register i(root);
            tree[i].size--;
            i = tree[i].daughter[x > tree[i].value]
        )
            if (tree[i].value == x) {
                if (--tree[i].count) { Splay(i); return; }
                Splay(i);
                if (not tree[i].daughter[0])
                    { connect(root = tree[i].daughter[1], 0, 0); return; }
                if (not tree[i].daughter[1])
                    { connect(root = tree[i].daughter[0], 0, 0); return; }
                unsigned int j(tree[i].daughter[0]);
                while (tree[j].daughter[1]) j = tree[j].daughter[1];
                splay(j, tree[i].daughter[0]);
                connect(tree[i].daughter[1], tree[i].daughter[0], 1),
                upto(tree[i].daughter[0]),
                connect(root = tree[i].daughter[0], 0, 0);
                return;
            }
    }
    unsigned int inline Get_Ranking(T const x) {
        unsigned int r(1);
        for (unsigned int register i(root); i;)
            if (tree[i].value == x)
                { Splay(i); return tree[tree[i].daughter[0]].size + 1; }
            else
                if (tree[i].value < x)
                    r += tree[tree[i].daughter[0]].size + tree[i].count,
                    i = tree[i].daughter[1];
                else
                    i = tree[i].daughter[0];
        return r;
    }
    unsigned int inline Get_Rank(unsigned int const x) {
        unsigned int r(1);
        for (unsigned int register i(root); true;) {
            if (
                r + tree[tree[i].daughter[0]].size <= x
                and x < r + tree[tree[i].daughter[0]].size + tree[i].count
            ) { Splay(i); return tree[i].value; }
            else
                if (x < r + tree[tree[i].daughter[0]].size)
                    i = tree[i].daughter[0];
                else
                    r += tree[tree[i].daughter[0]].size + tree[i].count,
                    i = tree[i].daughter[1];
        }
    }
    T inline Get_Less(T const x) {
        T r; unsigned int register li;
        for (unsigned int register i(root); i;)
            if (tree[i].value >= x) li = i, i = tree[i].daughter[0];
            else r = tree[li = i].value, i = tree[i].daughter[1];
        Splay(li);
        return r;
    }
    T inline Get_Greater(T const x) {
        T r; unsigned int register li;
        for (unsigned int register i(root); i;)
            if (tree[i].value <= x) li = i, i = tree[i].daughter[1];
            else r = tree[li = i].value, i = tree[i].daughter[0];
        Splay(li);
        return r;
    }
};