Solution -「SHOI 2013」发牌

cirnovsky /

看到好像没有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;
}