BZOJ 1208 宠物饲养所 Splay

要实现的操作是插入,删除,找到比指定值大的,小的值操作。

Splay的删除操作可以是直接用二叉搜索树的删除方式,或者是先将要删除的节点Splay到根,然后找到左子树中最大的节点,将其Splay到根的左儿子位置,此时这个节点必然是没有右子树的,然后直接把他当做根就好。

找大的值可以先找到如果要插入这个值会插在哪里,然后不执行操作,直接找前驱或者后继就可以了。

代码能力捉急,写了整整一天,各种debug蛋疼啊= =

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

using namespace std;

const int maxn = 2e6 + 10;
const int mod = 1000000;
const int PET = 0;
const int HUMAN = 1;
const int EMPTY = -1;
const int INF = INT_MAX / 3;
int ch[maxn][2], fa[maxn], val[maxn], sz, root;

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] != 0) {
		ch[fa[y]][y == ch[fa[y]][1]] = x;
	}
	ch[x][d] = y;
	fa[x] = fa[y];
	fa[y] = x;
}

int newNode(int &r, int father, int v) {
	r = ++sz;
	fa[r] = father; val[r] = v;
	ch[r][0] = ch[r][1] = 0;
	return r;
}

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

void debug(int root) {
	int lc = ch[root][0], rc = ch[root][1];
	printf("当前节点:%d(val = %d), lch: %d(val = %d), rch %d(val = %d), fa is %d\n",
		root, val[root], lc, val[lc], rc, val[rc], fa[root]);
	if (lc) debug(lc);
	if (rc) debug(rc);
}

int insert(int v) {
	if (root == 0) {
		newNode(root, 0, v);
		return root;
	}
	int u = root;
	while (ch[u][v > val[u]] != 0) 
		u = ch[u][v > val[u]];
	int r = newNode(ch[u][v > val[u]], u, v);
	splay(r, 0);
	return r;
}


//找后继
int findNext(int x) {
	//如果x节点有右子树
	if (ch[x][1] != 0) {
		//找到右子树中最小的节点
		int u = ch[x][1];
		while (ch[u][0] != 0) u = ch[u][0];
		return u;
	}
	//往上寻找
	int u = x;
	while (fa[u] != 0 && u != ch[fa[u]][0]) u = fa[u];
	return fa[u];
}

//用二叉搜索树删除节点的方式来删除节点
void remove(int x) {
	if (ch[x][0] == 0 && ch[x][1] == 0) {
		if (fa[x] == 0) root = 0;
		else ch[fa[x]][x == ch[fa[x]][1]] = 0;
	}
	else if (ch[x][0] == 0) {
		if (fa[x] == 0) {
			root = ch[x][1];
			fa[ch[x][1]] = 0;
		}
		else ch[fa[x]][x == ch[fa[x]][1]] = ch[x][1];
		fa[ch[x][1]] = fa[x];
	}
	else if (ch[x][1] == 0) {
		if (fa[x] == 0) {
			root = ch[x][0];
			fa[ch[x][0]] = 0;
		}
		else ch[fa[x]][x == ch[fa[x]][1]] = ch[x][0];
		fa[ch[x][0]] = fa[x];
	}
	else {
		int r = findNext(x);
		swap(val[r], val[x]);
		remove(r);
	}
}

//先splay到根然后删除
void remove_root() {
	int u = root;
	if (ch[u][0] == 0) {
		root = ch[u][1];
		fa[ch[u][1]] = 0;
	}
	else {
		//找到左子树中最大的值
		int x = ch[u][0];
		while (ch[x][1] != 0) x = ch[x][1];
		//splay到根的做子树
		splay(x, root);
		//debug(root);
		//此时x必然没有右子树,直接作为根
		ch[x][1] = ch[u][1];
		if (ch[u][1]) fa[ch[u][1]] = x;
		root = x; fa[x] = 0;
	}
	//debug(root);
}

int findValMinNext(int v) {
	int u = root;
	while (ch[u][v > val[u]] != 0) u = ch[u][v > val[u]];
	if (v >= val[u]) return u;
	while (fa[u] != 0 && val[fa[u]] > val[u]) u = fa[u];
	return fa[u];
}

int findValMaxNext(int v) {
	int u = root;
	while (ch[u][v > val[u]] != 0) u = ch[u][v > val[u]];
	if (v < val[u]) return u;
	while (fa[u] != 0 && val[fa[u]] <= val[u]) u = fa[u];
	return fa[u];
}

int main() {
	//freopen("INPUT.002", "r", stdin);
	//freopen("out.txt", "w", stdout);
	int n, state, cmd, st, ans;
	while (scanf("%d", &n) != EOF) {
		sz = root = ans = 0;
		state = EMPTY;
		for (int i = 1; i <= n; i++) {
			//debug(root);
			scanf("%d%d", &cmd, &st);
			if (state == EMPTY) {
				state = cmd; insert(st);
			}
			else if (state == cmd) insert(st);
			else {
				val[0] = INF;
				int g1 = findValMinNext(st), g2 = findValMaxNext(st);
				//run_test();
				//printf("g1 is %d, g2 is %d\n", val[g1], val[g2]);
				int v1 = abs(st - val[g1]), v2 = abs(st - val[g2]);
				if (v1 <= v2) {
					ans = (ans + v1) % mod;
					splay(g1, 0);  
					remove(root);
					//debug(root);
					//remove_root();
				}
				else {
					ans = (ans + v2) % mod;
					splay(g2, 0); 
					//debug(root);
					remove(root);
					//remove_root();
				}
				if (root == 0) state = EMPTY;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

  

posted @ 2015-02-06 11:49  acm_roll  阅读(238)  评论(0编辑  收藏  举报