平衡树(treap)学习笔记

        treap是一棵拥有键值、优先级、两种权值的树。对于键值而言,这棵树是排序二叉树;对于优先级而言,这棵树就是堆,即在这棵树的任意子树中根节点的优先值是最大的。treap树可以实现插入,删除节点,查询K大排名,查询数的排名,查询前驱和后继。

        定义:

struct Node
{
	Node*ch[2];
	int r,v,s,num;   //r为优先级, v是这个节点的权值, s代表这棵树的大小, num保存的时这个节点数的个数,也就是这个节点相同的数的个数. 
	Node(int v):v(v) {r=rand(); ch[0]=ch[1]=NULL; num=1;}
	int cmp(int x) const{
	    if(x==v) return -1;
	    else return (x>v?1:0);
	}
	void Maintain(){
		s=num;
		if(ch[0]!=NULL) s+=ch[0]->s;
		if(ch[1]!=NULL) s+=ch[1]->s;
	}
};
Node* root;

        加入节点:

void insert(Node* &o,int x)
{
	if(o==NULL) o=new Node(x);
	else
	{
		int d=o->cmp(x);
		if(d==-1) o->num+=1;
		else 
		{
		    insert(o->ch[d],x);
		    if(o->r < o->ch[d]->r) rotate(o,d^1);
		}
	}
	o->Maintain();
}

        删除节点:

void del(Node* &o,int x)
{
	int d=o->cmp(x);
	if(d==-1)
	{
		if(o->num==1)
		{
			if(o->ch[0]==NULL) o=o->ch[1];
			else if(o->ch[1]==NULL) o=o->ch[0];
			else 
			{
				int d2=(o->ch[1]->r > o->ch[0]->r?0:1);
				rotata(o,d2); del(o->ch[d2],x);
			}
		}
		else o->num-=1;
	}
	else del(o->ch[d],x);
	if(o!=NULL) o->Maintain();
}

        查询一个数的排名:

int rank(Node* &o,int x)
{
	int d=o->cmp(x);
	if(d==-1) return (o->ch[0]==NULL?1:o->ch[0]->s+1);
	else 
	{
		if(d==0) return rank(o->ch[0],x);
		else return (rank(o->ch[1],x)+(o->ch[0]==NULL?o->num:o->ch[0]->s+o->num));
	}
}

        查询排名为K的数:

int kth(Node* &o,int x)
{
	if(o==NULL||o->s<x||x<=0) return 0;
	int d=(o->ch[0]==NULL?0:o->ch[0]->s);
	if(d+1<=x&&x<=d+o->num) return o->v;
    if(x<=d) return kth(o->ch[0],x);
    else return kth(o->ch[1],x-d-o->num);
}

        查询一个数的前驱:

void pre(Node* &o,int x)
{
<span style="white-space:pre">	</span>if(o!=NULL)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">	</span>    if(x<=o->v)
<span style="white-space:pre">	</span>    {
<span style="white-space:pre">		</span>    if(o->ch[0]!=NULL) pre(o->ch[0],x);
            } 
            else 
            {
    <span style="white-space:pre">	</span>        ans=max(ans,o->v);
    <span style="white-space:pre">	</span>        if(o->ch[1]!=NULL) pre(o->ch[1],x);
            }
        }
}
//ans为一个全局变量,与下面查询后继时的一样 

        查询一个数的后继:

void sub(Node* &o,int x)
{
	if(o!=NULL)
	{
	    if(x>=o->v)
	    {
		    if(o->ch[1]!=NULL) sub(o->ch[1],x);
	    }
	    else
	    {
		    ans=min(ans,o->v);
		    if(o->ch[0]!=NULL) sub(o->ch[0],x);
	    }
	}
}

      当然treap还可以进行合并之类的操作,具体的会在永无乡中提到.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值