UOJ Logo ZTXX的博客

博客

题解 P3988 【[SHOI2013]发牌】

2019-12-21 11:38:49 By ZTXX

看到好像没有splay的题解,来补一波~~

找到1-x的区间,然后转到后面,在删除第一个就好了

需吸氧

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <utility>
#include <cctype>
#define mid (l + r >> 1)

using namespace std;

const int SIZE = 7e5 + 5;
struct SPLAY {
    int siz;
    int val;
    int ch[2];
    int fa;
} T[SIZE];
int root, n, R[SIZE], tot;

inline void update(int u) {
    T[u].siz = T[T[u].ch[0]].siz + T[T[u].ch[1]].siz + 1;
}

inline int make(int l, int r, int fa) {
    int u = ++tot;
    T[u].siz = 1;
    T[u].val = mid;
    T[u].ch[0] = T[u].ch[1] = 0;
    T[u].fa = fa;
    if (mid > l) T[u].ch[0] = make(l, mid - 1, u);
    if (mid < r) T[u].ch[1] = make(mid + 1, r, u);
    update(u);
    return u;
}

inline void rotate(int x) {
    int y = T[x].fa;
    int z = T[y].fa;
    int w = T[y].ch[1] == x;
    T[z].ch[T[z].ch[1] == y] = x;
    T[x].fa = z;
    T[y].ch[w] = T[x].ch[w ^ 1];
    T[T[x].ch[w ^ 1]].fa = y;
    T[x].ch[w ^ 1] = y;
    T[y].fa = x;
    update(y), update(x);
}

inline void splay(int x, int goal) {
    for (; T[x].fa ^ goal; rotate(x)) {
        int y = T[x].fa;
        int z = T[y].fa;
        if (z ^ goal)
            T[y].ch[1] ^ x ^ T[z].ch[1] ^ y ? rotate(x) : rotate(y);
    }
    if (!goal) root = x;
}

inline int getRank(int x) {
    int u = root;
    while (233) {
        if (x <= T[T[u].ch[0]].siz) u = T[u].ch[0];
        else {
            x -= T[T[u].ch[0]].siz + 1;
            if (!x) return u;
            u = T[u].ch[1];
        }
    }
}

inline int getcard(int x) {
    if (x) {
        splay(getRank(x), 0);
        int u = root;
        root = T[u].ch[1];
        T[root].fa = 0;
        T[u].ch[1] = 0;
        update(u);
        splay(getRank(T[root].siz), 0);
        if (u) T[u].fa = root;
        if (root) T[root].ch[1] = u, update(root);
    }
    int ranker = getRank(1);
    int res = T[ranker].val;
    splay(ranker, 0);
    if (T[ranker].ch[1])
        T[root = T[ranker].ch[1]].fa = 0;
    return res;
}

signed main() {
    scanf("%d", &n);
    root = make(1, n, 0);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &R[i]);
        printf("%d\n", getcard(R[i] % T[root].siz));
    }
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。