HDU 3436 Queue-jumpers Splay

这题用Splay写得我蛋疼菊紧,4000b的代码还有debug半天,看来我的splay姿势还不够好a = =

首先N是很大的,所以离散化是必然的,把要Top操作的和要Query操作的编号单独划分为一个区间,然后再中间会产生其他的区间,把这些区间缩点,然后离散化就好了。

三个操作其实不难实现,Top操作只要先把这个节点删除,然后把节点的其他值不变,key值变成一个极小值再重新插入就好,可以把极小值直接设成0,因为据说splay是稳定的,不过保险起见我还是设置了一个tpos变量维护了一下当前的极小值,还是比较方便的。

Rank操作其实就是一个找第k大,不同的就是这里节点本身的大小有可能不是1,要稍微处理一下。

Query操作就是找有几个节点比指定节点小,直接把这个节点splay到根,然后取左子树大小用即可。一开始我写成先找到这个节点,然后沿着父节点一路往上加的SB做法,直接TLE了两发,没有利用好splay的性质a,多伸展几下树也会平衡一点o(╯□╰)o

至于如何快速找到person,只要维护一个数组指向节点的编号就好。

不过感觉这题用线段树很好写a,只要在前面留Q个空位就好了。 。。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 3e5 + 10;
int ch[maxn][2], fa[maxn], rsize[maxn], size[maxn], key[maxn], nstr[maxn], chcnt, root;
int n, q, vnum[maxn], vcnt, qval[maxn], tpos, pos[maxn], pid[maxn];
int node_size[maxn], node_str[maxn], node_cnt;
char cmd[maxn][16];

inline void pushup(int x) {
	size[x] = rsize[x];
	for (int i = 0; i < 2; i++) if (ch[x][i]) {
		size[x] += size[ch[x][i]];
	}
}

int getID(int v) {
	return lower_bound(vnum, vnum + vcnt, v) - vnum;
}

void build_node() {
	//缩点
	for (int i = 1; i < vcnt; i++) {
		int tmp = vnum[i] - vnum[i - 1] - 1;
		if (tmp) {
			node_size[++node_cnt] = tmp;
			node_str[node_cnt] = vnum[i - 1] + 1;
		}
		node_size[++node_cnt] = 1;
		node_str[node_cnt] = vnum[i];
		pid[i] = node_cnt;
	}
	if (vnum[vcnt - 1] < n) {
		node_size[++node_cnt] = n - vnum[vcnt - 1];
		node_str[node_cnt] = vnum[vcnt - 1] + 1;
	}
}

int newNode(int &r, int father, int v, int rz, int ns) {
	r = ++chcnt;
	ch[r][0] = ch[r][1] = 0;
	rsize[r] = rz;
	key[r] = v;
	fa[r] = father;
	nstr[r] = ns;
	return r;
}

void build_tree(int l, int r, int &rt, int father) {
	int mid = l + r >> 1;
	rt = pos[mid] = newNode(rt, father, mid, node_size[mid], node_str[mid]);
	if (l < mid) build_tree(l, mid - 1, ch[rt][0], rt);
	if (r > mid) build_tree(mid + 1, r, ch[rt][1], rt);
	pushup(rt);
}

inline void rotate(int x, int d) {
	int y = fa[x];
	ch[y][d ^ 1] = ch[x][d];
	fa[ch[x][d]] = y;
	if (fa[y]) ch[fa[y]][y == ch[fa[y]][1]] = x;
	fa[x] = fa[y];
	ch[x][d] = y;
	fa[y] = x;
	pushup(x);
	pushup(y);
}

inline void splay(int x, int goal) {
	while (fa[x] != goal) {
		int y = fa[x], d = (x == ch[y][1]);
		if (fa[y] == goal) rotate(x, d ^ 1);
		else {
			int z = fa[y], d1 = (y == ch[z][1]);
			if (d == d1) {
				rotate(y, d ^ 1); rotate(x, d ^ 1);
			}
			else {
				rotate(x, d ^ 1); rotate(x, d1 ^ 1);
			}
		}
	}
	pushup(x);
	if (goal == 0) root = x;
}

inline int findMax(int rt) {
	while (ch[rt][1]) rt = ch[rt][1];
	return rt;
}

inline void remove(int x) {
	splay(x, 0);
	int lc = ch[x][0], rc = ch[x][1];
	if (lc) {
		int u = findMax(lc);
		splay(u, x);
		fa[u] = 0;
		if(rc) fa[rc] = u;
		ch[u][1] = rc;
		root = u;
		pushup(u);
	}
	else if(rc) {
		fa[rc] = 0;
		root = rc;
		pushup(rc);
	}
	else root = 0;
}

inline int insert(int v, int rz, int ns) {
	int u = root;
	if (root == 0) {
		newNode(root, 0, v, rz, ns);
		return root;
	}
	while (ch[u][v > key[u]]) u = ch[u][v > key[u]];
	int r = newNode(ch[u][v > key[u]], u, v, rz, ns);
	splay(r, 0);
	return r;
}

inline void setTop(int x) {
	x = pid[getID(x)];
	remove(pos[x]);
	pos[x] = insert(--tpos, node_size[x], node_str[x]);
}

inline int query(int x) {
	x = pos[pid[getID(x)]];
	splay(x, 0);
	return size[ch[x][0]] + 1;
}

inline int findkth(int rt, int k) {
	int lsize = size[ch[rt][0]];
	if (lsize >= k) return findkth(ch[rt][0], k);
	else if (lsize + rsize[rt] >= k) return nstr[rt] + k - lsize - 1;
	else return findkth(ch[rt][1], k - lsize - rsize[rt]);
}

int main() {
	int T; scanf("%d", &T);
	for (int kase = 1; kase <= T; kase++) {
		printf("Case %d:\n", kase);
		scanf("%d%d", &n, &q);
		//加入把要进行Top,和Query操作的值离散化
		vcnt = node_cnt = tpos = 0;
		vnum[vcnt++] = 0;
		chcnt = 0;
		for (int i = 1; i <= q; i++) {
			scanf("%s%d", cmd[i], &qval[i]);
			if (cmd[i][0] == 'T' || cmd[i][0] == 'Q') {
				vnum[vcnt++] = qval[i];
			}
		}
		sort(vnum, vnum + vcnt);
		vcnt = unique(vnum, vnum + vcnt) - vnum;
		build_node();
		build_tree(1, node_cnt, root, 0);
		for (int i = 1; i <= q; i++) {
			if (cmd[i][0] == 'T') setTop(qval[i]);
			else if (cmd[i][0] == 'R') printf("%d\n", findkth(root, qval[i]));
			else printf("%d\n", query(qval[i]));
		}
	}
	return 0;
}

  

posted @ 2015-02-07 16:28  acm_roll  阅读(207)  评论(0编辑  收藏  举报