zoukankan      html  css  js  c++  java
  • 普通平衡树

    题面:

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

    1. 插入x数
    2. 删除x数(若有多个相同的数,因只删除一个)
    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
    4. 查询排名为x的数
    5. 求x的前驱(前驱定义为小于x,且最大的数)
    6. 求x的后继(后继定义为大于x,且最小的数)

    Input

    第一行为n,表示操作的个数
    下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
    1.n的数据范围:n<=100000
    2.每个数的数据范围:[-2e9,2e9]

    Output

    对于操作3,4,5,6每行输出一个数,表示对应答案

    Sample Input

    10
    1 106465
    4 1
    1 317721
    1 460929
    1 644985
    1 84185
    1 89851
    6 81968
    1 492737
    5 493598

    Sample Output

    106465
    84185
    492737

    Solution:

    平衡树模板题
    因为需要查找排名,我们记录一个size[i]代表以i为根的子树的大小,因为treap满足二叉查找树的性质,所以就很好搞。
    因为可能会出现重复,所以我们可以再定义一个num来记录数值x在树中的个数
    详见代码

    Code:

    treap版

    #include<bits/stdc++.h>
    #define N 100001
    #define inf 1926081700
    using namespace std;
    int n;
    struct treap{
    	#define ls tree[q].l
    	#define rs tree[q].r
    	struct dqy{
    		int l,r;
    		int val,key;
    		int num,size;
    	}tree[N];
    	int root,tot;
    	int add(int v){
    		tree[++tot].val=v;
    		tree[tot].key=rand();
    		tree[tot].num=tree[tot].size=1;
    		return tot;
    	}
    	void update(int q){
    		tree[q].size=tree[ls].size+tree[rs].size+tree[q].num;
    	}//更新自己
    	void build(){
    		add(-inf),add(inf);
    		root=1;tree[1].r=2;
    		update(1);
    	}
    	int getrank(int q,int v){
    		if(q==0)return 0;
    		if(tree[q].val==v)return tree[ls].size+1;//左子树上的点必定小于自己
    		if(tree[q].val>v)return getrank(ls,v);//如果比自己小,跳到左子树上去找
    		return getrank(rs,v)+tree[ls].size+tree[q].num;
    		//否则跳到右子树,因为右子上的点必定大于左子树和父亲,所以还要加上左子树的大小和父亲的数量
    	}//查找排名
    	int getval(int q,int rk){
    		if(q==0)return inf;
    		if(tree[ls].size>=rk)return getval(ls,rk);//左子树小于自己,所以直接跳到左子树找
    		if(tree[ls].size+tree[q].num>=rk)return tree[q].val;
    		//因为不在左子树上,又在左子树和自己之间,所以肯定是自己
    		return getval(rs,rk-tree[ls].size-tree[q].num); //否则跳到右子树上找
    	}//查找权值
    	void zig(int &q){
    		int tmp=ls;
    		ls=tree[tmp].r;tree[tmp].r=q;q=tmp;
    		update(rs),update(q);
    	}//右旋
    	void zag(int &q){
    		int tmp=rs;
    		rs=tree[tmp].l;tree[tmp].l=q;q=tmp;
    		update(ls),update(q);
    	}//左旋
    	void insert(int &q,int v){
    		if(q==0){
    			q=add(v);
    			return ;
    		}//没有这个点就新建一个点出来
    		if(v==tree[q].val){
    			tree[q].num++;
    			update(q);
    			return ;
    		}//有这个点就直接给这个点的num++就可以了
    		if(v<tree[q].val){
    			insert(ls,v);
    			if(tree[q].key<tree[ls].key)zig(q);
    		}
    		else {
    			insert(rs,v);
    			if(tree[q].key<tree[rs].key)zag(q);
    		}
    		//找有没有这个点
    		update(q);
    	}
    	int precursor(int v){
    		int ans=1;
    		int q=root;
    		while(q){
    			if(v==tree[q].val){
    				if(ls>0){
    					q=ls;
    					while(rs>0)q=rs;
    					ans=q;
    				}
    				break;
    			}//要严格小于
    			if(tree[q].val<v&&tree[q].val>tree[ans].val)ans=q;
    			q=v<tree[q].val?ls:rs;
    		}
    		return tree[ans].val;
    	}//前驱
    	int successor(int v){
    		int ans=2;
    		int q=root;
    		while(q){
    			if(v==tree[q].val){
    				if(rs>0){
    					q=rs;
    					while(ls>0)q=ls;
    					ans=q;
    				}
    				break;
    			}//要严格大于
    			if(tree[q].val>v&&tree[q].val<tree[ans].val)ans=q;
    			q=v<tree[q].val?ls:rs;
    		}
    		return tree[ans].val;
    	}//后继
    	void remove(int &q,int v){
    		if(q==0)return ;
    		if(v==tree[q].val){//存在过这个点
    			if(tree[q].num>1){
    				tree[q].num--,update(q);
    				return ;
    			}//如果有这个点,直接num--
    			if(ls||rs){
    				if(rs==0||tree[ls].key>tree[rs].key)zig(q),remove(rs,v);
    				else zag(q),remove(ls,v);
    				update(q);
    			}//否则跳到子树上去找
    			else q=0;
    			return ;
    		}
    		v<tree[q].val?remove(ls,v):remove(rs,v);//跳到子树上去找
    		update(q);
    	}
    }T;
    inline int read(){ 
        int x=0,f=1;char ch=getchar(); 
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} 
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} 
        return x*f; 
    }
    int main(){
    	n=read();T.build();
    	for(int i=1;i<=n;i++){
    		int opt=read(),x=read();
    		switch(opt){
    			case 1:
    				T.insert(T.root,x);
    				break;
    			case 2:
    				T.remove(T.root,x);
    				break;
    			case 3:
    				printf("%d
    ",T.getrank(T.root,x)-1);//一开始插入了最值,所以要减一
    				break;
    			case 4:
    				printf("%d
    ",T.getval(T.root,x+1));
    				//因为是严格大于小于,所以要给排名加一
    				break;
    			case 5:
    				printf("%d
    ",T.precursor(x));
    				break;
    			default :
    				printf("%d
    ",T.successor(x));
    				break;
    		}
    	}
    	return 0; 
    }
    

    Splay版:

    #include<bits/stdc++.h>
    #define N 1000001
    #define inf 19260817
    using namespace std;
    struct Splay{
    	#define ls tree[q].son[0]
    	#define rs tree[q].son[1]
    	int root,tot;
    	struct dqy{
    		int fa;
    		int son[2];
    		int cnt,val,size;
    	}tree[N];
    	int newnode(int v){
    		tree[++tot].val=v;
    		tree[tot].size=tree[tot].cnt=1;
    		return tot;
    	}
    	void update(int q){tree[q].size=tree[ls].size+tree[rs].size+tree[q].cnt;}
    	int t(int x){return tree[tree[x].fa].son[1]==x;}
    	int find(int v){
    		int q=root;
    		while(tree[q].val!=v){
    			if(tree[q].val>v){if(ls)q=ls;else break;}
    			if(tree[q].val<v){if(rs)q=rs;else break;}
    		}
    		return q;
    	}
    	void rotate(int q){
    		int ret=t(q),f=tree[q].fa,s=tree[q].son[ret^1];
    		tree[f].son[ret]=s;if(s)tree[s].fa=f;tree[q].son[ret^1]=f;
    		tree[q].fa=tree[f].fa;if(tree[f].fa)tree[tree[f].fa].son[t(f)]=q;
    		tree[f].fa=q;update(f);update(q); 
    	}
    	void splay(int q){
    		while(tree[q].fa){
    			if(tree[tree[q].fa].fa)
    			if(t(tree[q].fa)==t(q))rotate(tree[q].fa);
    			rotate(q);
    		}
    		root=q;
    	}
    	void ins(int v){
    		if(!root){root=newnode(v);return ;}
    		int q=find(v);
    		if(tree[q].val==v){tree[q].cnt++;tree[q].size++;splay(q);return ;}
    		tree[newnode(v)].fa=q;tree[q].son[v>tree[q].val]=tot;
    		splay(tot);
    	}
    	void Delete(int v){
    		if(!root)return ;
    		int q=find(v);splay(q);
    		if(tree[q].val!=v||(--tree[q].cnt)){tree[q].size--;return ;}
    		if(!ls&&!rs){root=0;return ;}
    		if(!ls){root=rs;tree[rs].fa=0;return ;}
    		if(!rs){root=ls;tree[ls].fa=0;return ;}
    		int tmp=ls;while(tree[tmp].son[1])tmp=tree[tmp].son[1];
    		tree[ls].fa=0;splay(tmp);
    		tree[root].son[1]=rs;tree[rs].fa=root;
    	}
    	int getrk(int v){
    		int q=find(v);splay(q);
    		if(tree[q].val>=v)return tree[ls].size+1;
    		return tree[ls].size+tree[q].cnt+1; 
    	}
    	int getval(int rk){
    		int q=root;
    		while(rk){
    			if(tree[ls].size>=rk)q=ls;
    			else if(tree[ls].size+tree[q].cnt>=rk)break;
    			else  rk-=tree[ls].size+tree[q].cnt,q=rs;
    		}
    		return tree[q].val;
    	}
    	int precusor(int v){
    		int q=find(v);splay(q);
    		if(tree[q].val<v)return tree[q].val;
    		q=ls;while(rs)q=rs;
    		return tree[q].val;
    	}
    	int succesor(int v){
    		int q=find(v);splay(q);
    		if(tree[q].val>v)return tree[q].val;
    		q=rs;while(ls)q=ls;
    		return tree[q].val;
    	}
    }T;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    	return x*f;
    }
    int main(){
    	int n=read();
    	for(int i=1;i<=n;i++){
    		int opt=read(),v;
    		switch(opt){
    			case 1:v=read();T.ins(v);break;
    			case 2:v=read();T.Delete(v);break;
    			case 3:v=read();printf("%d
    ",T.getrk(v));break;
    			case 4:v=read();printf("%d
    ",T.getval(v));break;
    			case 5:v=read();printf("%d
    ",T.precusor(v));break;
    			case 6:v=read();printf("%d
    ",T.succesor(v));break;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    sublime text
    php 实例说明 socket通信机制
    nusaop 关于webService
    vim操作集合
    gitHud设置公钥
    redis在window安装并启动
    百度云api 添加标注
    微信小程序bindTap获取对应值
    Java导出excel表
    linux 常用命令
  • 原文地址:https://www.cnblogs.com/NLDQY/p/10081900.html
Copyright © 2011-2022 走看看