HDU 1890--Robotic Sort(Splay Tree)

题意:每次找出第i大的数的位置p输出,然后将i~p之间的数反转。

题解:每次把要的区间转成一棵子树,然后更新。因为每次将第i小的数转到了了i,所以k次操作后,可知前k个数一定是最小的那k个数,所以以后的操作一定不会和前k个数有关,所以每次操作后可以把操作完的数删掉。所以每次把p转到根,然后翻转左子树,删除根就可以了。(也就是p不需要翻转

这个splay处理比较特殊,每个结点的序号就是一开始的位置。splaytree中第i个结点的序号就是第i个数一开始的位置,然后对于每个数排序,记录一开始的位置,就可以在树中直接找到要操作的结点了。

总之。。很神奇。。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int INF = 0x5f5f5f5f;
const int N = 100005;

int root, tot;
int sz[N], pre[N], ch[N][2], rev[N];

bool which_son(int o) { //判断一个结点是不是父结点的右儿子
    return ch[pre[o]][1] == o;
}

void update_rev(int o) {
    if (!o) return ;
    swap(ch[o][0], ch[o][1]);
    rev[o] ^= 1;
}

void push_up(int o) {
    sz[o] = sz[ch[o][0]] + sz[ch[o][1]] + 1;
}

void push_down(int o) {
    if (rev[o]) {
        update_rev(ch[o][0]);
        update_rev(ch[o][1]);
        rev[o] = 0;
    }
}

void build(int &o, int l, int r, int fa) {
    if (l > r) return ;
    int m = (l+r) >> 1;
    o = m;
    pre[o]= fa;
    ch[o][0] = ch[o][1] = 0;
    sz[o] = 1;
    rev[o] = 0;
    build(ch[o][0], l, m-1, o);
    build(ch[o][1], m+1, r, o);
    push_up(o);
}

void init(int n) {
    root = tot = 0;
    pre[0] = sz[0] = ch[0][1] = ch[0][0] = rev[0] = 0;
    build(root, 1, n, 0);
    push_up(root);
}

void rotate(int o, int d) {
    int fa = pre[o];
    push_down(fa);
    push_down(o);
    ch[fa][!d] = ch[o][d];
    pre[ch[o][d]] = fa;
    pre[o] = pre[fa];
    if (pre[fa]) ch[pre[fa]][which_son(fa)] = o;
    pre[o] = pre[fa];
    ch[o][d] = fa;
    pre[fa] = o;
    push_up(fa);
}

void splay(int o, int goal) {
    push_down(o);
    while (pre[o] != goal) {
        if (pre[pre[o]] == goal) {
            push_down(pre[o]);
            push_down(o);
            rotate(o, !which_son(o));
        } else {
            push_down(pre[pre[o]]);
            push_down(pre[o]);
            push_down(o);
            int fa = pre[o];
            int d = !which_son(fa);
            if (ch[fa][d] == o) {
                rotate(o, !d);
                rotate(o, d);
            } else {
                rotate(fa, d);
                rotate(o, d);
            }
        }
    }
    push_up(o);
    if (goal == 0) root = o;
}

int get_max(int o) {
    push_down(o);
    while (ch[o][1]) {
        o = ch[o][1];
        push_down(o);
    }
    return o;
}

void remove() {
    if (ch[root][0] == 0) {
        root = ch[root][1];
        pre[root] = 0;
    } else {
        int m = get_max(ch[root][0]);
        splay(m, root);
        ch[m][1] = ch[root][1];
        pre[ch[root][1]] = m;
        root = m;
        pre[root] = 0;
        push_up(root);
    }
}

struct node {
    int v, id;
    bool operator<(const node rhs) const {
        if (v == rhs.v) return id < rhs.id;
        return v < rhs.v;
    }
} a[N];

int main()
{
    //freopen("in.txt", "r", stdin);
    int n;
    while (~scanf("%d", &n) && n) {
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i].v);
            a[i].id = i;
        }
        sort(a+1, a+1+n);
        init(n);
        for (int i = 1; i < n; ++i) {
            splay(a[i].id, 0);
            printf("%d ", sz[ch[a[i].id][0]]+i);
            update_rev(ch[a[i].id][0]);
            remove();
        }
        printf("%d\n", n);
    }

    return 0;
}

 

posted @ 2016-09-02 11:13  我不吃饼干呀  阅读(276)  评论(0编辑  收藏  举报