Treap(AVL)板子

13 篇文章 1 订阅
5 篇文章 0 订阅

神仙东西

高级的呀,100多行,调了我亿点点时间。哦也,过了
直接放代码,代码有注释。
题目链接

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define N 100000
#define INF 1000000000 
using namespace std;
int n,opt,x;
int son[N+1][2],val[N+1],data[N+1],size[N+1],tot,cnt[N+1],root;
int born(int v)//新建节点,插入时用 
{
	val[++tot]=v;
	data[tot]=rand();//随机化优先级 
	size[tot]=1;
	cnt[tot]=1;
	return tot;
}
void push_up(int id)//更新id点的子树大小 
{ size[id]=size[son[id][0]]+size[son[id][1]]+cnt[id];}
void build()
{
	root=born(-INF),son[root][1]=born(INF);//右子树比根节点大 
	push_up(root);//更新 
}
void spin(int &id,int dir)
{
	int temp=son[id][dir^1];
	son[id][dir^1]=son[temp][dir];//将要旋转的根的左(右)儿子的右(左)儿子作为根的(左右)儿子 
	son[temp][dir]=id,id=temp;//将原根节点的左(右)儿子于原根节点连上,并作为新的根 
	push_up(son[id][dir]),push_up(id);
}
void ins(int &id,int v)
{
	if(!id)
	{
		id=born(v);//此节点为空,直接插入 
		return;
	}
	if(v==val[id]) cnt[id]++;
	else
	{
		int pd=v>val[id]?1:0;//看一下向哪里走 
		ins(son[id][pd],v);
		if(data[son[id][pd]]>data[id]) spin(id,pd^1);
	}
	push_up(id);//更新一下本节点的信息 
}
void del(int &id,int v)//删除函数 
{
	if(!id) return;//找不到,直接返回 
	if(v==val[id])//找到 
	{
		if(cnt[id]>1) //副本大于一,那么直接减 
		{
			cnt[id]--,push_up(id);
			return;
		}
		if(son[id][1]||son[id][0])//如果不是的话要通过旋转把此节点放到最底下进行操作 
		{
				if(!son[id][1]||data[son[id][1]]<data[son[id][0]]) spin(id,1),del(son[id][1],v);
				else spin(id,0),del(son[id][0],v);
				push_up(id);//时时刻刻记得更新 
		}
		else id=0;//如果已经是叶子节点了,那就直接删 
		return;
	}
    v<val[id]?del(son[id][0],v):del(son[id][1],v);//看往哪走 
    push_up(id);
} 
int get_rank(int id,int v)
{
	if(!id) return -2;//就是说如果没有的话那么因为有INF,所以返回值会加一 
	if(v==val[id]) return size[son[id][0]]+1;
	else if(v<val[id]) return get_rank(son[id][0],v);
	else return size[son[id][0]]+cnt[id]+get_rank(son[id][1],v);
}
int get_val(int id,int rank)
{
	if(!id) return INF;//好像根本没有这种样例qaq 
	if(rank<=size[son[id][0]]) return get_val(son[id][0],rank);
	else if(rank<=size[son[id][0]]+cnt[id]) return val[id];
	else return get_val(son[id][1],rank-cnt[id]-size[son[id][0]]);
}
int get_pre(int v)
{
	int id=root,pre;
	while(id)
    {
    	if(val[id]<v) pre=val[id],id=son[id][1];
    	else id=son[id][0];
	}
	return pre;
}
int get_next(int v)//这好理解,两个相反。哈哈 
{
	int id=root,nxt;
	while(id)
	{
		if(val[id]>v) nxt=val[id],id=son[id][0];
		else id=son[id][1];
	}
	return nxt;
} 
int qread()
{
	int x=0,pd=1;
	char c=getchar();
	while(c>'9'||c<'0') 
    {
    	if(c=='-') pd=-1;
    	c=getchar();
	}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x*pd;
}
void ks(int r)
{
	if(r<0) putchar('-'),r=-r;//就不知道为什么有负数?(是我没看题了) 
	if(r>=10) ks(r/10);
	putchar(r%10+'0');
}
int main()
{
	n=qread();
	build();
	while(n--)
	{
		opt=qread(),x=qread();
		if(opt==1) ins(root,x);
		if(opt==2) del(root,x);
		if(opt==3) ks(get_rank(root,x)-1),putchar('\n');//同下 
		if(opt==4) ks(get_val(root,x+1)),putchar('\n');//额,在树根有-INF 
		if(opt==5) ks(get_pre(x)),putchar('\n');
		if(opt==6) ks(get_next(x)),putchar('\n');
	}
    return 0;	
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值