• 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
    ",
    		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
    ", 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
    ", ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    AC日记——[HNOI2008]GT考试 bzoj 1009
    AC日记——[SCOI2009]游戏 bzoj 1025
    AC日记——[HNOI2010]BOUNCE 弹飞绵羊 洛谷 P3203
    AC日记——旅游 bzoj 2157
    NOIP模拟2017.6.11解题报告
    AC日记——【模板】Link Cut Tree 洛谷 P3690
    AC日记——[SDOI2010]大陆争霸 洛谷 P3690
    [NOI2010]超级钢琴 倍增
    [HNOI2004]L语言 字典树 记忆化搜索
    对拍
  • 原文地址:https://www.cnblogs.com/rolight/p/4276783.html
Copyright © 2020-2023  润新知