BZOJ3224/LOJ104 普通平衡树 treap(树堆)

您需要写一种数据结构,来维护一些数,其中需要提供以下操作:
1. 插入x
2. 删除x(若有多个相同的数,因只删除一个)
3. 查询x的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

1.n的数据范围:$n<=100000$
2.每个数的数据范围:$[-2e9,2e9]$

题解:

  二叉搜索树可以完成目标,但是单次操作的时间复杂度可能退化为线性

  因此使用平衡二叉树,$treap$(树堆)

  树堆是各类平衡树中,速度和代码复杂度比较均衡的一个

  速度比splay快且好写,比sbt,替罪羊慢但简单,个人觉得代码比较简单

  BZOJ

  LOJ

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
const int maxm=1e6+10;
int casn,n,m,k;
#define nd treap[now]
#define ndl treap[treap[now].l]
#define ndr treap[treap[now].r]
#define ndt treap[tmp]
struct node {
	int l,r,val,num,size,rnd;
}treap[maxn];
int cnt,root,ans;
inline void resize(int now){
	nd.size=ndl.size+ndr.size+nd.num;
}
inline void rturn(int &now){
	int tmp=nd.l;
	nd.l=ndt.r,ndt.r=now;
	ndt.size=nd.size;
	resize(now);
	now=tmp;
}
inline void lturn(int &now){
	int tmp=nd.r;
	nd.r=ndt.l,ndt.l=now;
	ndt.size=nd.size;
	resize(now);
	now=tmp;
}
void insert(int &now,int val){
	if(!now) {
		now=++cnt;
		nd=(node){0,0,val,1,1,rand()};
		return ;
	}
	nd.size++;
	if(val==nd.val)nd.num++;
	else if(val>nd.val){
		insert(nd.r,val);
		if(ndr.rnd<nd.rnd) lturn(now);
	}else{
		insert(nd.l,val);
		if(ndl.rnd<nd.rnd) rturn(now);
	}
}
void erase(int &now,int val){
	if(!now) return ;
	if(val==nd.val){
		if(nd.num>1){
			nd.num--,nd.size--;
			return ;
		}
		if(nd.r*nd.l==0) now=nd.l+nd.r;
		else {
			if(ndl.rnd<ndr.rnd) rturn(now);
			else lturn(now);
			erase(now,val);
		}
	}else {
		nd.size--;
		if(val>nd.val) erase(nd.r,val);
		else erase(nd.l,val);
	}
}
int query_rank(int now,int val){
	if(!now) return 0;
	if(val==nd.val)return ndl.size+1;
	if(val>nd.val) return ndl.size+nd.num+query_rank(nd.r,val);
	return query_rank(nd.l,val);
}
int query_val(int now,int rank){
	if(!now) return 0;
	if(rank<=ndl.size) return query_val(nd.l,rank);
	if(rank-ndl.size<=nd.num) return nd.val;
	return query_val(nd.r,rank-ndl.size-nd.num);
}
int query_pre(int now,int val){
	if(!now) return ans;
	if(val<=nd.val) return query_pre(nd.l,val);
	ans=nd.val;
	return query_pre(nd.r,val);
}
int query_sub(int now,int val){
	if(!now) return ans;
	if(val>=nd.val) return query_sub(nd.r,val);
	ans=nd.val;
	return query_sub(nd.l,val);
}
int main(){
//#define test
#ifdef test
  freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif
	int root=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		if(a==1) insert(root,b);
		if(a==2) erase(root,b);
		if(a==3) printf("%d\n",query_rank(root,b));
		if(a==4) printf("%d\n",query_val(root,b));
		if(a==5) printf("%d\n",query_pre(root,b));
		if(a==6) printf("%d\n",query_sub(root,b));
	}
#ifdef test
  fclose(stdin);fclose(stdout);system("out.txt");
#endif
  return 0;
}

 

posted @ 2018-06-22 07:21  nervending  阅读(244)  评论(0编辑  收藏  举报