【BZOJ 3224】普通平衡树

【题目】

传送门

Description

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

Input

第一行为 n,表示操作的个数,下面 n 行每行有两个数 opt 和 x,opt 表示操作的序号(1 ≤ opt ≤ 6)

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

HINT

n 的数据范围:n ≤ 100000

每个数的数据范围:[ -2\times 10^9 , 2\times 10^9 ]

 

【分析】

平衡树板子题。。。

就是常规的平衡树操作,我就得 Treap 要比 Splay 好写一点,就写的 Treap

 

【代码】

#include<ctime>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define inf (int)2e+9
#define lc(x) son[x][0]
#define rc(x) son[x][1]
using namespace std;
int tot,val[N],num[N],size[N],weight[N],son[N][2];
void pushup(int root)
{
	size[root]=size[lc(root)]+size[rc(root)]+num[root];
}
void rotate(int &root,int t)
{
	int x=son[root][t];
	son[root][t]=son[x][t^1];
	son[x][t^1]=root;
	pushup(root),pushup(x);
	root=x;
}
void insert(int &root,int x)
{
	if(root)
	{
		if(val[root]==x)
		  num[root]++;
		else
		{
			int t=val[root]<x;
			insert(son[root][t],x);
			if(weight[son[root][t]]<weight[root])
			  rotate(root,t);
		}
	}
	else
	{
		root=++tot;
		val[tot]=x;
		num[tot]=1;
		weight[tot]=rand();
	}
	pushup(root);
}
void remove(int &root,int x)
{
	if(val[root]==x)
	{
		if(num[root]>1)
		  num[root]--;
		else
		{
			if(!lc(root)&&!rc(root))
			{
				root=0;
				return;
			}
			rotate(root,weight[lc(root)]<weight[rc(root)]);
			remove(root,x);
		}
	}
	else
	  remove(son[root][val[root]<x],x);
	pushup(root);
}
int findrank(int root,int x)
{
	if(!root)  return 0;
	if(val[root]<x)  return size[lc(root)]+num[root]+findrank(rc(root),x);
	return findrank(lc(root),x);
}
int findkth(int root,int x)
{
	if(size[lc(root)]<x&&size[lc(root)]+num[root]>=x)  return val[root];
	if(x<=size[lc(root)])  return findkth(lc(root),x);
	return findkth(rc(root),x-size[lc(root)]-num[root]);
}
int findpre(int root,int x)
{
	if(!root)  return -inf;
	if(val[root]<x)  return max(val[root],findpre(rc(root),x));
	return findpre(lc(root),x);
}
int findsuf(int root,int x)
{
	if(!root)  return inf;
	if(val[root]>x)  return min(val[root],findsuf(lc(root),x));
	return findsuf(rc(root),x);
}
int main()
{
	int n,i,s,x,root=0;
	srand(time(0));
	scanf("%d",&n);
	for(i=1;i<=n;++i)
	{
		scanf("%d%d",&s,&x);
		if(s==1)  insert(root,x);
		if(s==2)  remove(root,x);
		if(s==3)  printf("%d\n",findrank(root,x)+1);
		if(s==4)  printf("%d\n",findkth(root,x));
		if(s==5)  printf("%d\n",findpre(root,x));
		if(s==6)  printf("%d\n",findsuf(root,x));
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值