P3960 NOIP2017 提高组 列队

P3960 NOIP2017 提高组 列队

将每一行的第1到m-1个和第m列分离出来
分析知这n+1个“区间”要维护弹出第k个和插入最后
使用平衡树,一个区间若没有被算则用[l,r]表示(方伯伯的OJ)

点击查看代码

#include <stdio.h>
#include <string.h>
const int N = 3e5 + 5;
typedef long long LL;
struct Node {
	int son[2], fa;
	LL l, r, size; // l,r 为区间左右端点
} tr[N * 8];
int idx, n, m, q;
void push_up(int u) {
	tr[u].size = tr[tr[u].son[0]].size + tr[tr[u].son[1]].size + (tr[u].r - tr[u].l + 1);
}
void rotate(int x) {
	int y = tr[x].fa, z = tr[y].fa, k = tr[y].son[1] == x;
	tr[tr[z].son[tr[z].son[1] == y] = x].fa = z;
	tr[tr[y].son[k] = tr[x].son[!k]].fa = y;
	tr[tr[x].son[!k] = y].fa = x;
	push_up(y), push_up(x);
}
struct Splay {
	int root;
	void splay(int x, int rt) {
		static int y, z;
		while(tr[x].fa != rt) {
			y = tr[x].fa, z = tr[y].fa;
			if(z != rt) rotate((tr[y].son[1] == x) ^ (tr[z].son[1] == y) ? x : y);
			rotate(x);
		}
		if(!rt) root = x;
	}
	void init(LL l, LL r) {
		root = ++ idx;
		tr[idx].fa = tr[idx].son[0] = tr[idx].son[1] = 0;
		tr[idx].l = l, tr[idx].r = r, tr[idx].size = r - l + 1;
	}
	int build(int fa, int l, int r) {
		if(l > r) return 0;
		int mid = (l + r) >> 1, u = ++ idx;
		tr[u].fa = fa, tr[u].l = tr[u].r = LL(mid) * m;
		tr[u].son[0] = build(u, l, mid - 1);
		tr[u].son[1] = build(u, mid + 1, r);
		push_up(u); return u;
	}
	// 将u的前k个保留,后面的作为返回值的新节点
	int split(int u, int k) {
		int v = ++ idx;
		tr[v].l = tr[u].l + k, tr[v].r = tr[u].r;
		tr[u].r = tr[u].l + k - 1;
		// 将v节点放到u的后继节点的左儿子并旋转到根
		if(tr[u].son[1]) {
			int t = tr[u].son[1];
			while(tr[t].son[0]) t = tr[t].son[0];
			tr[tr[t].son[0] = v].fa = t;
		} else tr[tr[u].son[1] = v].fa = u;
		splay(v, 0);
		return v;
	}
	LL popkth(int k) {
		int u = root, lssz;
		while(u) {
			lssz = tr[tr[u].son[0]].size;
			if(lssz >= k) u = tr[u].son[0];
			else if(lssz + (tr[u].r - tr[u].l + 1) >= k) {
				k -= lssz;
				if(k < tr[u].r - tr[u].l + 1) split(u, k);
				if(k > 1) u = split(u, k - 1);
				break;
			} else k -= lssz + (tr[u].r - tr[u].l + 1), u = tr[u].son[1];
		}
		// 现在u为这个单独的节点,将其删除
		splay(u, 0);
		tr[tr[u].son[0]].fa = tr[tr[u].son[1]].fa = 0;
		if(tr[u].son[0]) {
			int t = tr[u].son[0];
			while(tr[t].son[1]) t = tr[t].son[1];
			splay(t, 0);
			tr[tr[t].son[1] = tr[u].son[1]].fa = t;
			push_up(t);
		} else root = tr[u].son[1];
		return tr[u].l;
	}
	void push(LL val) {
		int u = root, fu = 0;
		while(u) fu = u, u = tr[u].son[1];
		u = ++ idx, tr[u].l = tr[u].r = val, tr[u].fa = fu, tr[u].size = 1;
		if(fu) tr[fu].son[1] = u;
		splay(u, 0);
	}
} tree[N];
int main() {
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= n; i ++) tree[i].init(m * LL(i - 1) + 1, m * LL(i) - 1);
	tree[0].root = tree[0].build(0, 1, n);
	LL tmp; // 答案
	for(int i = 1, x, y; i <= q; i ++) {
		scanf("%d%d", &x, &y);
		tree[x].push(tree[0].popkth(x));
		printf("%lld\n", tmp = tree[x].popkth(y));
		tree[0].push(tmp);
	}
	return 0;
}
posted @ 2022-09-28 11:59  azzc  阅读(42)  评论(0编辑  收藏  举报