HDU 1890 splay

HDU

题意:每次输出pos[i]后翻转[i,pos[i]]。

裸splay。
如何获得当前i的位置困扰了好久。
网上都是使用另一种魔性splay写法,直接把某一指针提到根……然而我是lrj写法无力啊……
@plm大神表示记录每个点代表的指针即可。事实上还要记录父指针。
寻找i的位置的过程最后我研究出这种写法:如果它是父亲的右孩子,那么计数加上左孩子size+1(父节点本身);左孩子则不管;若有翻转标记则不动标记直接ret = size(o) + 1 - ret;把计数“反”过来。注意特判初始节点。

码(11784K, 436ms)

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
template<class T> 
inline void read(T& x)
{
    char c = getchar(); T p = 1, n = 0;
    while(c < '0' || c > '9'){if(c == '-') p = -1; c = getchar();}
    while(c >= '0' && c <= '9'){n = n * 10 + c - '0'; c = getchar();}
    x = p * n;
}
template<class T, class U>
inline void read(T& x, U& y){read(x), read(y);}
template<class T, class U, class V>
inline void read(T& x, U& y, V& z){read(x), read(y), read(z);}

const int maxn = 1e5 + 100;

struct Node
{
    int v;
    bool rev;
    int size;
    Node *fa;
    Node *ch[2];
    Node(int a = 0, Node *b = NULL) : v(a), rev(false), size(1), fa(b) {ch[0] = ch[1] = NULL;}
} *root;

#define lc(o) (o -> ch[0])
#define rc(o) (o -> ch[1])
#define v(o) (o -> v)
#define fa(o) (o -> fa)
#define rev(o) (o -> rev)
#define size(o) (o ? o -> size : 0)

inline int cmp(Node *o, int k) {return size(lc(o)) == k - 1 ? -1 : (size(lc(o)) < k ? 1 : 0);}
inline void pushdown(Node* &o) {if(!o||!rev(o))return;if(lc(o))rev(lc(o)) ^= 1; if(rc(o))rev(rc(o)) ^= 1; swap(lc(o), rc(o)); rev(o) = false;}
inline void maintain(Node* &o) {if(!o)return; o -> size = size(lc(o)) + size(rc(o)) + 1;}

inline void rotate(Node* &o, int d)
{
    pushdown(o); 
    Node *p = o -> ch[d ^ 1];
    pushdown(p);
    o -> ch[d ^ 1] = p -> ch[d];    if(p -> ch[d])fa(p -> ch[d]) = o; fa(p) = fa(o);
    p -> ch[d] = o;                    fa(o) = p;
    maintain(o); maintain(p);
    o = p;    
}

void splay(Node* &o, int k)
{
    if(!o)
        return;
    pushdown(o);
    int d = cmp(o, k);
    if(d == 1)
        k -= size(lc(o)) + 1;
    if(d != -1)
    {
        Node *p = o -> ch[d];
        pushdown(p);
        int d2 = cmp(p, k);
        int k2 = (d2 == 0 ? k : k - size(lc(p)) - 1);
        if(d2 != -1)
        {
            splay(p -> ch[d2], k2);
            if(d == d2)
                rotate(o, d ^ 1);
            else
                rotate(o -> ch[d], d);
        }
        rotate(o, d ^ 1);
    }
}

int a[maxn] = {0}, b[maxn] = {0}, c[maxn] = {0};
Node *table[maxn] = {NULL};
inline bool compare(int x, int y) {return a[x] == a[y] ? x < y : a[x] < a[y];}
void build(Node* &o, int x, int y, Node *fa = NULL)
{
    if(x > y)
        return;
    int m = (x + y) / 2;
    if(!o)
        o = new Node(a[m], fa);
    table[c[m]] = o;
    build(lc(o), x, m - 1, o);
    build(rc(o), m + 1, y, o);
    maintain(o);
}

int ret = 0;
void count(Node* o, bool first = false)
{
    if(first)
    {
        ret += size(lc(o)) + 1;
        if(rev(o))
            ret = size(o) + 1 - ret;
    }
    if(!fa(o))
        return;
    if(rc(fa(o)) == o)
        ret += size(lc(fa(o))) + 1;
    if(rev(fa(o)))
        ret = size(fa(o)) + 1 - ret;
    count(fa(o));
}

void go(Node* &o, int i)
{
    ret = 0;
    count(table[i], true);
    if(i != 1) printf(" ");
    printf("%d", ret + i - 1);
    if(size(o) == 1)
        return;
    splay(o, ret);
    if(lc(o))
        rev(lc(o)) ^= 1;
    if(!rc(o))
        o = lc(o), fa(o) = NULL;
    else if(!lc(o))
        o = rc(o), fa(o) = NULL;
    else
    {
        splay(rc(o), 1);
        fa(lc(o)) = rc(o);
        lc(rc(o)) = lc(o);
        o = rc(o);
        fa(o) = NULL;
        maintain(o);
    }
}

int main()
{
    int n;
    while(read(n), n)
    {
        root = NULL;
        for(int i = 1; i <= n; i++)
            read(a[i]);
        for(int i = 1; i <= n; i++)
            b[i] = i;
        sort(b + 1, b + n + 1, compare);
        for(int i = 1; i <= n; i++)
            c[b[i]] = i;
        build(root, 1, n);
        for(int i = 1; i <= n; i++)
            go(root, i);
        puts("");
    }
    return 0;
}

标签: splay

添加新评论