Treap简介

292 篇文章 1 订阅
281 篇文章 1 订阅

定义

树堆,在数据结构中也称Treap,是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。

简单点说,Treap=tree+heap

实现

Treap实际上是对BST的优化。因为BST有可能退化成链而导致查询复杂度变成 O(n) ,而Treap多了heap这个性质,使得它的期望复杂度可以达到 O(nlog2n)

而维护heap时需要旋转操作,这里给一张图体会一下:

这里写图片描述

那heap这个性质是怎么来的呢?

在插入一个节点时,我们随机地给它一个优先级,然后和维护heap一样维护这个优先级。插入时如果优先级比根大就旋转。删除时和插入反过来就可以了,把需要删除的节点不断旋转至叶子节点,然后删去即可。

操作

由于Treap的本质就是BST,因此它支持BST的所有操作。

代码实现(模板)

BZOJ3224洛谷P3369)为例:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define N 100000
using namespace std;
struct node{
    int w,p,size,rnd,to[2];
    //w:权值 p:有多少权值是相等的 size:子树中的节点个数
    //rnd:优先级 to[]:儿子
}t[N+5];
int n,rt,nd,p;
void rtt(int &x,int fl){//rotate(旋转)
    int s=t[x].to[fl];
    t[x].to[fl]=t[s].to[fl^1];
    t[s].to[fl^1]=x;
    t[s].size=t[x].size;
    t[x].size=t[t[x].to[0]].size+t[t[x].to[1]].size+t[x].p;
    x=s; return;
}
void nsrt(int &x,int w){//insert(插入)
    if (!x){
        t[x=++nd].w=w; 
        t[x].rnd=rand();
        t[x].p=t[x].size=1;
        return;
    }
    t[x].size++;
    if (t[x].w==w) t[x].p++;
    else if (t[x].w<w){
        nsrt(t[x].to[1],w);
        if (t[t[x].to[1]].rnd<t[x].rnd) rtt(x,1);
    }
    else{
        nsrt(t[x].to[0],w);
        if (t[t[x].to[0]].rnd<t[x].rnd) rtt(x,0);
    }
}
void dlt(int &x,int w){//delete(删除)
    if (!x) return;
    if (t[x].w==w){
        if (t[x].p>1){ t[x].p--; t[x].size--; return; }
        if (!(t[x].to[0]*t[x].to[1])) x=t[x].to[0]+t[x].to[1];
        else if (t[t[x].to[0]].rnd<t[t[x].to[1]].rnd) rtt(x,0),dlt(x,w);
        else rtt(x,1),dlt(x,w);
    }
    else{
        t[x].size--;
        if (t[x].w<w) dlt(t[x].to[1],w);
        else dlt(t[x].to[0],w);
    }
}
int srch_rk(int x,int w){//search_rank(查询排名)
    if (!x) return 0;
    if (t[x].w==x) return t[t[x].to[0]].size+1;
    else if (t[x].w<w)
        return t[t[x].to[0]].size+t[x].p+srch_rk(t[x].to[1],w);
    else return srch_rk(t[x].to[0],w);
}
int srch_nm(int x,int w){//search_num(查询数)
    if (!x) return 0;
    if (t[t[x].to[0]].size>=w)
        return srch_nm(t[x].to[0],w);
    else if (t[t[x].to[0]].size+t[x].p<w)
        return srch_nm(t[x].to[1],w-t[t[x].to[0]].size-t[x].p);
    else return t[x].w;
}
int srch_frnt(int x,int w){//search_front(查询前驱)
    if (!x) return 0;
    if (t[x].w<w){
        int k=srch_frnt(t[x].to[1],w);
        if (!k) return t[x].w;
        else return k;
    }
    else return srch_frnt(t[x].to[0],w);
}
int srch_bck(int x,int w){//search_back(查询后继)
    if (!x) return 0;
    if (t[x].w>w){
        int k=srch_bck(t[x].to[0],w);
        if (!k) return t[x].w;
        else return k;
    }
    else return srch_bck(t[x].to[1],w);
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        int flag,x; 
        scanf("%d%d",&flag,&x);
        switch (flag){
            case 1: nsrt(rt,x); break;
            case 2: dlt(rt,x); break;
            case 3: printf("%d\n",srch_rk(rt,x)+1); break;//这里记得+1
            case 4: printf("%d\n",srch_nm(rt,x)); break;
            case 5: printf("%d\n",srch_frnt(rt,x)); break;
            case 6: printf("%d\n",srch_bck(rt,x)); break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值