zoukankan      html  css  js  c++  java
  • [洛谷P3835]【模板】可持久化平衡树

    题目大意:

    来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):

    1. 插入x数

    2. 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)

    3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)

    4. 查询排名为x的数

    5. 求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)

    6. 求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)

    和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)

    每个版本的编号即为操作的序号(版本0即为初始状态,空树)

    题解:可持久化平衡树,就是在merge和split的时候不修改原来的点,改为新增一个点存放

    卡点:1.未考虑第一次插入因为树中没有节点,与其他的不同,需要特殊考虑,而导致后面出错

    C++ Code:

    #include <cstdio>
    #include <cstdlib>
    #define maxn 500010
    using namespace std;
    const int inf = 2147483647;
    int n, ver, op, x;
    int root[maxn];
    struct Tree {
    	int lc[maxn * 50], rc[maxn * 50], val[maxn * 50], num[maxn * 50], sz[maxn * 50]; //val值,num堆值 
    	int idx, ta, tb, tmp, res;
    	void debug(int p) {
    		if (lc[p]) debug(lc[p]);
    		printf("%d : val %d  lc %d  rc %d
    ", p, val[p], lc[p], rc[p]);
    		if (rc[p]) debug(rc[p]);
    	}
    	void cpy(int cur, int ver) {
    		lc[cur] = lc[ver];
    		rc[cur] = rc[ver];
    		val[cur] = val[ver];
    		num[cur] = num[ver];
    		sz[cur] = sz[ver];
    	}
    	void update(int rt) {sz[rt] = sz[lc[rt]] + sz[rc[rt]] + 1;}
    	int nw(int p) {
    		val[++idx] = p;
    		sz[idx] = 1;
    		num[idx] = rand();
    		return idx;
    	}
    	void split(int rt, int p, int &x, int &y) {
    		if (!rt) x = y = 0;
    		else {
    			if (val[rt] <= p) {
    				x = ++idx;
    				cpy(x, rt);
    				split(rc[x], p, rc[x], y);
    				update(x);
    			} else {
    				y = ++idx;
    				cpy(y, rt);
    				split(lc[y], p, x, lc[y]);
    				update(y);
    			}
    		}
    	}
    	int merge(int x, int y) {
    		if (!x || !y) return x | y;
    		int o;
    		if (num[x] < num[y]) {
    			o = ++idx;
    			cpy(o, x);
    			rc[o] = merge(rc[o], y);
    		} else {
    			o = ++idx;
    			cpy(o, y);
    			lc[o] = merge(x, lc[o]);
    		}
    		update(o);
    		return o;
    	}
    	void insert(int &rt, int x) {
    		if (!rt) rt = nw(x);
    		else {
    			split(rt, x, ta, tb);
    	//		printf("Debug:%d %d
    ", ta, tb);
    			rt = merge(merge(ta, nw(x)), tb);
    		}
    	}
    	void erase(int &rt, int x) {
    		split(rt, x, ta, tb);
    		split(ta, x - 1, ta, tmp);
    //		printf("%d %d %d
    ", ta, tb, tmp);
    		if (val[tmp] != x) rt = merge(merge(ta, tmp), tb);
    		else rt = merge(merge(ta, merge(lc[tmp], rc[tmp])), tb);
    	}
    	int gtrnk(int rt, int x) {
    		split(rt, x - 1, ta, tb);
    		res = sz[ta] + 1;
    		merge(ta, tb);
    		return res;
    	}
    	int gtkth(int rt, int k) {
    		while (true) {
    			if (k <= sz[lc[rt]]) rt = lc[rt];
    			else {
    				if (k == sz[lc[rt]] + 1) return val[rt];
    				else k -= sz[lc[rt]] + 1, rt = rc[rt];
    			}
    		}
    	}
    	int pre(int rt, int x) {
    		split(rt, x - 1, ta, tb);
    		if (!ta) res = -inf;
    		else res = gtkth(ta, sz[ta]), merge(ta, tb);
    		return res;
    	}
    	int nxt(int rt, int x) {
    		split(rt, x, ta, tb);
    		if (!tb) res = inf;
    		else res = gtkth(tb, 1), merge(ta, tb);
    		return res;
    	}
    } T;
    int main() {
    	srand(20040826);
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d%d%d", &ver, &op, &x);
    		root[i] = root[ver];
    		switch (op) {
    			case 1: {
    				T.insert(root[i], x); 
    //				T.debug(root[i]);
    				break;
    			}
    			case 2: {
    				T.erase(root[i], x); 
    //				T.debug(root[i]);
    				break;
    			}
    			case 3: {
    				printf("%d
    ", T.gtrnk(root[i], x)); 
    //				T.debug(root[i]);
    				break;
    			}
    			case 4: {
    				printf("%d
    ", T.gtkth(root[i], x)); 
    //				T.debug(root[i]);
    				break;
    			}
    			case 5: {
    				printf("%d
    ", T.pre(root[i], x)); 
    //				T.debug(root[i]);
    				break;
    			}
    			case 6: {
    				printf("%d
    ", T.nxt(root[i], x)); 
    //				T.debug(root[i]);
    				break;
    			}
    		}
    	}
    	return 0;
    } 
    

      

  • 相关阅读:
    linux C++类中成员变量和函数的使用
    使用linux backtrace打印出错函数堆栈信息
    R String 操作
    make
    *.efasta to fasta format transformation
    python os 库
    Ch12 Resampling statistics and bootstrapping
    Updating an R installation
    10 步让你成为更优秀的程序员
    Working with large datasets
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9354944.html
Copyright © 2011-2022 走看看