Treap

Treap

         Treap=Tree+Heap,Treap是一个二叉搜索树,它的左右子树都分别是一个Treap,和一般二叉排序树不同的是,Treap记录一个额外的数据(v),就是优先级(rank)。Treap在以关键字构成二叉排序树的同时,还满足堆的性质,不过Treap不一定是完全二叉树,而堆必须是完全二叉树.

 

1.结构体定义:

struct data{

         int l,r;  //左右子树

int v;  //当前节点的值

int size; //由该节点为根构成的子树的大小

int rnd; //当前节点的优先级

int w; //和当前节点值相同的个数

}tr[MAXN];

 

2.Treap的性质:

(1)    如果b是a的左子树,那么tree[a].v>tree[b].v;

(2)    如果c是a的右子树,那么tree[a].v<tree[c].v;

(3)    如果b,c分别是a的左右子树,那么tree[a].rank<tree[b].rank&& tree[a].rank<tree[c].rank;

 

3.Treap的旋转:跟普通的旋转一样

代码实现:

void update(int k)//更新结点信息

{

         tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;

}

void rturn(int &k)

{

         int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;

         tr[t].size=tr[k].size;update(k);k=t;

}

void lturn(int &k)

{

         int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;

         tr[t].size=tr[k].size;update(k);k=t;

}

 

4.Treap的插入:

(1)按照二叉树的插入方法,将结点插入到树中

(2)根据堆的性质(我们这里为最小堆)和优先级的大小调整结点位置。

代码实现:

void insert(int &k,int x){

         if(k==0){

                   size++;k=size;

                   tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand();

                   return;

         }

         tr[k].size++;

    if(tr[k].v==x)tr[k].w++;

         else if(x>tr[k].v){

                   insert(tr[k].r,x);

                   if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k); //维护堆性质

         }

         else {

                   insert(tr[k].l,x);

                   if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);

         }

}

 

5.Treap的删除:

(1)利用二叉树的性质,找到和x值相同的节点

(2)如果和x值相同的节点的个数有多个,那么只需要将size和w减一即可

(3)如果和x值相同的节点的个数只有一个,而且其存在一个子结点,那么当前需要删除的结点的值应该更新为存在的子节点的值,如果存在两个子结点,那么判断两个子结点的优先级,优先级值小的被更新为删除结点的值。

代码实现:

void del(int &k,int x){

    if(k==0)return;

         if(tr[k].v==x){

                   if(tr[k].w>1){

                            tr[k].w--;tr[k].size--;return;//若不止相同值的个数有多个,删去一个

                   }

                   if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;//有一个儿子为空

                   else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd)

                            rturn(k),del(k,x);

                   else lturn(k),del(k,x);

         }

         else if(x>tr[k].v)

                   tr[k].size--,del(tr[k].r,x);

         else tr[k].size--,del(tr[k].l,x);

}

 

6.Treap的应用:

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

代码实现:

int query_rank(int k,int x){

    if(k==0)return 0;

         if(tr[k].v==x)return tr[tr[k].l].size+1;

         else if(x>tr[k].v)

                   return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x);

         else return query_rank(tr[k].l,x);

}

(2) 查询排名为x的数

代码实现:

int query_num(int k,int x){

    if(k==0)return 0;

         if(x<=tr[tr[k].l].size)

                   return query_num(tr[k].l,x);

    else if(x>tr[tr[k].l].size+tr[k].w)

                   return query_num(tr[k].r,x-tr[tr[k].l].size-tr[k].w);

    else return tr[k].v;

}

(4)    求x的前驱(前驱定义为小于x,且最大的数)和x的后继(后继定义为大于x,且最小的数)

代码实现:

int ans=0;

void query_pro(int k,int x){  //前驱

    if(k==0)return;

    if(tr[k].v<x){

                   ans=k;query_pro(tr[k].r,x);

         }

    else query_pro(tr[k].l,x);

}

cout<<tree[ans].v<<endl;

void query_sub(int k,int x){  //后继

         if(k==0)return;

         if(tr[k].v>x){

                   ans=k;query_sub(tr[k].l,x);

         }

         else query_sub(tr[k].r,x);

}

cout<<tree[ans].v<<endl;

 

7.完整代码:

struct data{

         int l,r,v,size,rnd,w;

}tr[MAXN];

int n,size,root,ans;

void update(int k)//更新结点信息

{

         tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;

}

void rturn(int &k)

{

         int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;

         tr[t].size=tr[k].size;update(k);k=t;

}

void lturn(int &k)

{

         int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;

         tr[t].size=tr[k].size;update(k);k=t;

}

void insert(int &k,int x)

{

         if(k==0)

         {

                   size++;k=size;

                   tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand();

                   return;

         }

         tr[k].size++;

    if(tr[k].v==x)tr[k].w++;//每个结点顺便记录下与该节点相同值的数的个数

         else if(x>tr[k].v)

         {

                   insert(tr[k].r,x);

                   if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);//维护堆性质

         }

         else

         {

                   insert(tr[k].l,x);

                   if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);

         }

}

void del(int &k,int x)

{

    if(k==0)return;

         if(tr[k].v==x)

         {

                   if(tr[k].w>1)

                   {

                            tr[k].w--;tr[k].size--;return;//若不止相同值的个数有多个,删去一个

                   }

                   if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;//有一个儿子为空

                   else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd)

                            rturn(k),del(k,x);

                   else lturn(k),del(k,x);

         }

         else if(x>tr[k].v)

                   tr[k].size--,del(tr[k].r,x);

         else tr[k].size--,del(tr[k].l,x);

}

int query_rank(int k,int x)

{

    if(k==0)return 0;

         if(tr[k].v==x)return tr[tr[k].l].size+1;

         else if(x>tr[k].v)

                   return tr[tr[k].l].size+tr[k].w+query_rank(tr[k].r,x);

         else return query_rank(tr[k].l,x);

}

int query_num(int k,int x)

{

    if(k==0)return 0;

         if(x<=tr[tr[k].l].size)

                   return query_num(tr[k].l,x);

    else if(x>tr[tr[k].l].size+tr[k].w)

                   return query_num(tr[k].r,x-tr[tr[k].l].size-tr[k].w);

    else return tr[k].v;

}

void query_pro(int k,int x)

{

    if(k==0)return;

    if(tr[k].v<x)

         {

                   ans=k;query_pro(tr[k].r,x);

         }

    else query_pro(tr[k].l,x);

}

void query_sub(int k,int x)

{

         if(k==0)return;

         if(tr[k].v>x)

         {

                   ans=k;query_sub(tr[k].l,x);

         }

         else query_sub(tr[k].r,x);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值