• bzoj 3224,tyvj 1728普通平衡树


    原题地址


    这道题涵盖了平衡树的基本操作。。。

    先关注操作三,它指出要输出最小的排名,因此我们可以将重复的元素存在一个节点内,代码实现很简单。。。

    插入操作已讲。。。

    那么怎样删除呢?

    首先我们找到被删的点,如果它是重复的(该元素还剩很多个),那么就把个数减一即可。

    否则我们可以采用像堆的方式,将这个元素通过旋转不断地下移。。。

    问题来了,下移的时候是选择左旋还是右旋呢?

    左旋是将右边的点换到上面,右旋是将左边的点换到上面,由于我的随机值是大根堆(大的在下,小的在上)。那么我就应该把随机值小的儿子旋到上面来。(和堆的原理一样)根据这个来决定是左旋还是右旋。。旋转后将当前点移动到旋转的那个儿子上[旋转后原来的点就变成了儿子,儿子正是原来的点];就这样反复执行,直到当前点的两个儿子都为Null 了[注:Null是本人造出来的值,为了弥补指针的不足,具体详见代码] ,就把当前点变为Null,就成功删去啦!


    怎样用平衡树来查前驱呢?

    如果我们要查点x的前驱,从root开始, 如果当前点的值是小于x点的,那么前驱有可能在当前点的右子树中,但当前点的的右子树中的所有点可能都大于x点,所以前驱也有可能就是当前点。。。面对这种情况我们应先搜右子树,看有没有结果,然后确定答案;如果当前点是大于等于x点的,那么很显然前驱在当前点的左子树中,就把当前点变为左儿子就行了

    查后继的事情就交给读者自己想了。

    至于3,4两个查询操作,对于读者来说也很简单了,就不说了。。


    那么基本的treap模板就打出来了

    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cctype>
    #include<cmath>
    #include<vector>
    const int N = 1e5 + 7,INF = 0x7fffffff;
    #define Ran1221() ((rand() << 13) + (rand() << 6) + rand ())
    #define Ran12() (Ran1221() + Ran1221() + Ran1221() + 1)
    
    class Treap {
    	private :
    		struct Node {
    			Node *son[2];
    			int size,num,data,hr;
    			Node () {}
    			Node (int data,Node *fl) : data(data) { size = num = 1; son[0] = son[1] = fl; hr = Ran12(); }
    			void update () { size = son[0] -> size + son[1] -> size + num; }
    		}*pool,*Null,*root,meme[N];
    		
    		int ball;
    		
    		void rotate (Node *&T,bool v) {
    			Node *Tt = T -> son[v];
    			T -> son[v] = Tt -> son[v^1];
    			Tt -> son[v^1] = T;
    			T -> update(); Tt -> update();
    			T = Tt;
    		}
    		
    		int Precursor (Node *&T) {
    			if(T == Null) return T -> data;
    			if(T -> data >= ball) return Precursor (T -> son[0]);
    			int k = Precursor (T -> son[1]);
    			if(k == Null -> data) return T -> data;
    			return k; 
    		}
    		
    		int Subsequent (Node *&T) {
    			if(T == Null) return T -> data;
    			if(T -> data <= ball) return Subsequent (T -> son[1]);
    			int k = Subsequent (T -> son[0]);
    			if(k == Null -> data) return T -> data;
    			return k;
    		}
    		
    		void Print (Node *&T) {
    			if(T == Null) return ;
    			Print (T -> son[0]);
    			for(int i=1;i<=T->num;++i) printf("%d ",T -> data);
    			Print (T -> son[1]);
    		}
    		
    		void Insert (Node *&T) {
    			if(T == Null) { T = new (pool++) Node (ball,Null); return; }
    			if(T -> data == ball) {
    				++ T -> num; ++ T -> size; return ;
    			}
    			int v = ball > T -> data;
    			Insert (T -> son[v]);
    			if(T -> son[v] -> hr < T -> hr) rotate (T,v);
    			else T -> update();
    		}
    		
    		int sum;
    		
    		void Rank (Node *&T) {
    			if(T == Null) return ;
    			if(T -> data > ball) Rank (T -> son[0]);
    			else {
    				sum += T -> son[0] -> size;
    				if(T -> data < ball) sum += T -> num , Rank (T -> son[1]);
    			}
    		}
    		
    		void Delete (Node *&T) {
    			if(T == Null) return ;
    			if(T -> data == ball) {
    				if(T -> num > 1) {
    					-- T -> num;
    					-- T -> size;
    					return ;
    				}
    				if(T -> son[0] == Null || T -> son[1] == Null) {
    					int v = T -> son[1] != Null;
    					T = T -> son[v];
    					return ;
    				}
    				int v = T -> son[1] -> hr < T -> son[0] -> hr;
    				rotate (T,v);
    				Delete (T -> son[v^1]);
    			} else {
    				int v = ball > T -> data;
    				Delete (T -> son[v]);	
    			}
    			T -> update();
    		}
    		
    		int TheNo (Node *&T) {
    			if(T == Null) return 0;
    			if(ball <= T -> son[0] -> size) return TheNo (T -> son[0]);
    			if(ball <= T -> son[0] -> size + T -> num) return T -> data;
    			ball -= T -> son[0] -> size + T -> num; return TheNo (T -> son[1]);
    		}
    		
    		
    		
    	public :
    		Treap () { Null = new Node (); Null -> size = Null -> num = 0; Null -> data = -INF;}
    		void Pri () { Print(root); }
    		void clear () { pool = meme; root = Null; }
    		void Ins (int xxx) { ball = xxx; Insert(root); }
    		int Ran (int xxx) { ball = xxx; sum = 0; Rank (root); return sum; }
    		void Del (int xxx) { ball = xxx; Delete(root); }
    		int The (int xxx) { ball = xxx; return TheNo(root); }
    		int Pre (int xxx) { ball = xxx; return Precursor(root);} 
    		int Sub (int xxx) { ball = xxx; return Subsequent(root); } 
    		
    }treap;
    
    int opt,w,Q;
    
    int main () {
    	freopen("3224.in","r",stdin);
    	freopen("3224.out","w",stdout);
    	scanf("%d",&Q); treap.clear();
    	while (Q--) {
    		scanf("%d%d",&opt,&w);
    		if(opt == 1) treap . Ins(w);
    		if(opt == 2) treap . Del(w);
    		if(opt == 3) printf("%d
    ",treap . Ran(w) + 1);
    		if(opt == 4) printf("%d
    ",treap . The(w));
    		if(opt == 5) printf("%d
    ",treap . Pre(w));
    		if(opt == 6) printf("%d
    ",treap . Sub(w));
    	}
    	return 0;
    }


    That is all , thank you for watching.

  • 相关阅读:
    TSQL Challenge 1
    CTE的使用
    编号问题
    C语言结构体(sizeof长度)偏移量的简单研究
    【更新中】树的遍历
    【更新中】C语言语法汇总(仅记录遇到的坑)
    windows修改PowerShell(命令提示符)默认中文编码方式
    “人工智能”并不可怕
    学习《操作系统》收获
    人类大脑只开发了10%? I don't think so.
  • 原文地址:https://www.cnblogs.com/dcoi-king/p/5353662.html
Copyright © 2020-2023  润新知