1004 - treap - 普通平衡树

继续平衡树……

普通平衡树

描述

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

  1. 插入x数

  2. 删除x数(若有多个相同的数,因只删除一个)

  3. 查询x数的排名(若有多个相同的数,因输出最小的排名)

  4. 查询排名为x的数

  5. 求x的前驱(前驱定义为小于x,且最大的数)

  6. 求x的后继(后继定义为大于x,且最小的数)

输入

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

输出

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

样例输入


1 10 
1 20 
1 30 
3 20 
4 2 
2 10 
5 25 
6 -1

样例输出


20 
20 
20

提示

n<=100000 所有数字均在-10^7到10^7内

 

分析

板子题,板子题,板子题

背模板,背模板,背模板

一开始用splay写,结果可能是因为第一次写吧,各种bugs,就放弃了。。。

听gsj大佬说treap版本的很好写,就去敲了个模板

在算后继的时候出了一点小差错,由于此题要求后继定义为大于x的最小值,所以不能取到等于x,那么在处理的时候就要注意大于等于的问题,然后就没什么要注意的了吧

 

代码

#include<bits/stdc++.h>
#define N 500000
#define in read()
#define inf (int)2e+9
using namespace std;
int n,ch[N][2],sze[N],rt=0,num[N],pri[N];
int a[N],tot=0;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return f==1?res:-res;
}
void pushup(int x) {	sze[x]=sze[ch[x][0]]+sze[ch[x][1]]+num[x];}
//the first time I wrote function"pushup",I naively wrote "sze[x]+="
//how stupid I was! 
void rotate(int &rt,int t){
	int x=ch[rt][t];
	ch[rt][t]=ch[x][t^1];
	ch[x][t^1]=rt;
	pushup(rt);pushup(x);//
	rt=x;//you can not change the order
}
void insert(int &rt,int x){
	if(rt){
		if(a[rt]==x) num[rt]++;
		else{
			int t=x>a[rt];
			insert(ch[rt][t],x);
			if(pri[ch[rt][t]]<pri[rt]) rotate(rt,t);
		} 
	}
	else{
		rt=++tot;sze[tot]=1;num[tot]=1;
		a[tot]=x;pri[tot]=rand();
	}
	pushup(rt);//always remember to update
}
void del(int &rt,int x){
	if(a[rt]==x){
		if(num[rt]>1) num[rt]--;
		else{
			if(!ch[rt][0]&&!ch[rt][1]){
				rt=0;
				return;
			}
			else{
				rotate(rt,pri[ch[rt][0]]<pri[ch[rt][1]]);
				del(rt,x);
			}
		}
	}
	else del(ch[rt][x>a[rt]],x);
	pushup(rt);
}
int findrank(int rt,int x){
	if(!rt) return 0;
	if(x>a[rt]) return sze[ch[rt][0]]+num[rt]+findrank(ch[rt][1],x);
	return findrank(ch[rt][0],x);
}
int findkth(int rt,int x){//find the xth 
	if(x>sze[ch[rt][0]]&&x<=sze[ch[rt][0]]+num[rt]) return a[rt];
	if(x<=sze[ch[rt][0]]) return findkth(ch[rt][0],x);
	return findkth(ch[rt][1],x-sze[ch[rt][0]]-num[rt]);
}
int pre(int rt,int x){
	if(!rt) return -inf;
	if(x>a[rt]) return max(a[rt],pre(ch[rt][1],x));
	return pre(ch[rt][0],x);
}
int suf(int rt,int x){
	if(!rt) return inf;
	if(x>=a[rt]) return suf(ch[rt][1],x);//just here,pay attetion to the mark"="
	return min(a[rt],suf(ch[rt][0],x));
}
int main(){
	n=in;
	srand(time(0));
	int opt,x;
	while(n--){
		opt=in;x=in;
		if(opt==1) insert(rt,x);
		if(opt==2) del(rt,x);
		if(opt==3) printf("%d\n",findrank(rt,x)+1);
		if(opt==4) printf("%d\n",findkth(rt,x));
		if(opt==5) printf("%d\n",pre(rt,x));
		if(opt==6) printf("%d\n",suf(rt,x));
	}
	return 0;
}

 

后续应该会补一下splay版本的,望监督

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值