普通平衡树

题面:

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

  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\n",T.getrank(T.root,x)-1);//一开始插入了最值,所以要减一
				break;
			case 4:
				printf("%d\n",T.getval(T.root,x+1));
				//因为是严格大于小于,所以要给排名加一
				break;
			case 5:
				printf("%d\n",T.precursor(x));
				break;
			default :
				printf("%d\n",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\n",T.getrk(v));break;
			case 4:v=read();printf("%d\n",T.getval(v));break;
			case 5:v=read();printf("%d\n",T.precusor(v));break;
			case 6:v=read();printf("%d\n",T.succesor(v));break;
		}
	}
	return 0;
}
posted @ 2018-12-07 11:25  DQY_dqy  阅读(188)  评论(2编辑  收藏  举报