• BZOJ3224 Tyvj 1728 普通平衡树(Treap)


    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

    题目链接:BZOJ3224

    正解:$Treap$

    解题报告:

      $Treap$其实就是二叉搜索树啦,加入了随机化权值之后可以保证树的形态比较平衡。

      $Treap$既是一棵二叉搜索树又是一个大根堆(小根堆也行,随意啦),每次$insert$了之后给这个节点$rand$一个权值就好了,然后每次需要保证堆的性质,所以要维护一个向上旋转的操作。

      这就是旋转式的$Treap$了,挺simple的

    //It is made by ljh2000
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #include <string>
    #include <complex>
    #include <bitset>
    using namespace std;
    typedef long long LL;
    typedef long double LB;
    typedef complex<double> C;
    const double pi = acos(-1);
    const int MAXN = 100011;
    int n,rt,tot,tr[MAXN][2],size[MAXN],r[MAXN],val[MAXN];
    //维护按权值的二叉搜索树,同时是随机权值的大根堆
    //相等的均靠左
    inline void update(int x){ size[x]=size[tr[x][0]]+size[tr[x][1]]+1; }
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void R(int &p,bool k){//把x的左/右儿子旋转上来
    	int t=tr[p][k]; tr[p][k]=tr[t][k^1]; tr[t][k^1]=p;
    	update(p); update(t); p=t;
    }
    
    inline void insert(int &p,int x){
    	if(!p) { p=++tot; val[p]=x; size[p]=1; r[p]=rand(); return ; }
    	size[p]++;//!!!
    	if(x<=val[p]) insert(tr[p][0],x); else insert(tr[p][1],x);
    	bool k=(x>val[p]);
    	if(r[ tr[p][k] ] > r[p]) R(p,k);//不满足大根堆性质,往上旋转
    }
    
    inline void out(int &p){//删除当前节点,不断旋转,直到没有左儿子或者没有右儿子就可以结束了
    	if(!tr[p][0] || !tr[p][1]) { p=tr[p][0]+tr[p][1]; return ; }
    	bool k=(r[ tr[p][1] ]>r[ tr[p][0] ]);//把key偏大的那个儿子旋转上来
    	R(p,k); size[p]--;//!!!
    	out(tr[p][k^1]);
    }
    
    inline void del(int &p,int k){//把当前子树中rank为k的结点删除
    	size[p]--;//!!!在最前面呀...
    	if(size[tr[p][0]]+1==k) { out(p); return ; }
    	if(size[tr[p][0]]>=k) del(tr[p][0],k);
    	else del(tr[p][1]/*!!!*/,k-size[tr[p][0]]-1);
    }
    
    inline int kth(int x,int k){//查询rank为k的数,rank最小的那个
    	while(x) {
    		if(size[tr[x][0]]+1==k) return val[x];
    		if(k<=size[tr[x][0]]) x=tr[x][0];
    		else k-=size[tr[x][0]]+1,x=tr[x][1];
    	}
    	return 0;
    }
    
    inline int rank(int x,int k){//查询>=k的第一个数的rank,最靠左的那个
    	int tot=1;
    	while(x) {
    		if(k<=val[x]) x=tr[x][0];
    		else tot+=size[tr[x][0]]+1,x=tr[x][1];
    	}
    	return tot;
    }
    
    inline void work(){
    	srand(23333);
    	n=getint(); int type,x;
    	while(n--) {
    		type=getint(); x=getint();
    		if(type==1) {
    			insert(rt,x);
    		}
    		else if(type==2) {
    			del(rt,rank(rt,x));
    		}
    		else if(type==3) {
    			printf("%d
    ",rank(rt,x));
    		}
    		else if(type==4) {
    			printf("%d
    ",kth(rt,x));
    		}
    		else if(type==5) {
    			printf("%d
    ", kth( rt, rank(rt,x)-1 ) );
    		}
    		else {
    			printf("%d
    ", kth( rt, rank(rt,x+1) ) );
    		}
    	}
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("3224.in","r",stdin);
    	freopen("3224.out","w",stdout);
    #endif
        work();
        return 0;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    Nginx 安装与配置
    CentOS 7 下安装 MySQL 5.7
    使用yum命令报错File "/usr/bin/yum", line 30 except KeyboardInterrupt, e:
    Linux7 安装python3.5.4
    Java基础---Java 类
    Java基础---Java 练习题49
    Apache tomcat
    html 基础
    Java基础---Java 数组
    hibernate的查询方式的介绍(一)
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6636496.html
Copyright © 2020-2023  润新知