Treap学习小计

3 篇文章 0 订阅
2 篇文章 0 订阅

啊啊啊啊,终于学会打treap了啊啊啊啊啊

一个小故事

从前,Tree和Heap相遇了,他们相爱了,于是生下了一个孩子,他叫什么呢?于是他姓Tr名字叫eap,所以他就叫Treap(啦啦啦啦啦啦啦)

Treap的性质

既然他爸是Tree,他妈是Heap,那必定会遗传他爸和他妈的血统啊。
所以他是棵Balanced Binary Tree,同时从其每个点的键值来看,他的形态又是一棵不严格的Heap,当然由于这是从他妈那遗传的,所以他仅仅满足了Heap中:一个点的键值小于(或大于)他的两个儿子的键值。

插入

对于一个点的插入,我们像普通的二叉搜索树一样找到相应位置然后插入,注意我们要维护其heap的形态,所以我们要将新插入的点到根节点的路径类似普通的Heap的方法一样向上,但是由于这是棵二叉搜索树,于是我们要用旋转而非交换。

删除

删除一个节点,若其只有一个儿子或没有儿子,那么其直接用其儿子代替它或直接删掉,若它有两个儿子,那么看它的左右儿子那个键值小,若左儿子小则右旋,右儿子小则左旋,然后继续删除。

其它操作

由于其它操作与普通平衡树基本一样,我就不说了哈。

code(向hzw学习了呀)

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>

#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)

using namespace std;

typedef long long LL;
typedef double db;

int get(){
    char ch;
    int s=0;
    bool pd=0;
    while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');
    if (ch=='-')pd=1;
    else s=ch-'0';
    while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';
    if (pd)return -s;
    return s;
}

const int N = 100010;

struct point{
    int l,r,tot,v,key,w;
}tree[N];
int tot,n,root;

void updata(int x){
    tree[x].tot=tree[tree[x].l].tot+tree[tree[x].r].tot+tree[x].w;
}

void rturn(int &x){
    int y=tree[x].l;tree[x].l=tree[y].r;tree[y].r=x;
    tree[y].tot=tree[x].tot;updata(x);x=y;
}

void lturn(int &x){
    int y=tree[x].r;tree[x].r=tree[y].l;tree[y].l=x;
    tree[y].tot=tree[x].tot;updata(x);x=y;
}

void insert(int &now,int x){
    if (!now){
        tree[now=++tot].v=x;
        tree[now].key=rand();
        tree[now].tot=tree[now].w=1;
        return;
    }
    tree[now].tot++;
    if (x==tree[now].v)tree[now].w++;
    else
    if (x<tree[now].v){
        insert(tree[now].l,x);
        if (tree[tree[now].l].key<tree[now].key)rturn(now);
    }
    else{
        insert(tree[now].r,x);
        if (tree[tree[now].r].key<tree[now].key)lturn(now);
    }
}

void del(int &now,int x){
    if (tree[now].v==x){
        if (tree[now].w>1){
            tree[now].w--;
            tree[now].tot--;
            return;
        }
        if (tree[now].l*tree[now].r==0)now=tree[now].l+tree[now].r;
        else{
            if (tree[tree[now].l].key<tree[tree[now].r].key)rturn(now),del(now,x);
            else lturn(now),del(now,x);
        }
        return;
    }
    tree[now].tot--;
    if (tree[now].v>x)del(tree[now].l,x);
    else del(tree[now].r,x);
}

int rank(int now,int x){
    if (!now)return -N;
    if (tree[now].v==x)return tree[tree[now].l].tot+1;
    if (x<tree[now].v)return rank(tree[now].l,x);
    return tree[tree[now].l].tot+tree[now].w+rank(tree[now].r,x);
}

int kth(int now,int k){
    if (!now)return 0;
    if (tree[tree[now].l].tot<k&&k<=tree[tree[now].l].tot+tree[now].w)
    return now;
    if (k<=tree[tree[now].l].tot)return kth(tree[now].l,k);
    return kth(tree[now].r,k-tree[tree[now].l].tot-tree[now].w);
}

int pre(int now,int x){
    if (!now)return 0;
    if (tree[now].v<x){
        int v=pre(tree[now].r,x);
        if (v)return v;
        return now;
    }
    return pre(tree[now].l,x);
}

int suf(int now,int x){
    if (!now)return 0;
    if (tree[now].v>x){
        int v=suf(tree[now].l,x);
        if (v)return v;
        return now;
    }
    return suf(tree[now].r,x);
}

int main(){
    n=get();
    srand(57789);
    int tim=0;
    fo(i,1,n){
        int w,opt=get(),x=get();
        switch(opt){
        case 1:insert(root,x);break;
        case 2:del(root,x);break;
        case 3:printf("%d\n",rank(root,x));break;
        case 4:w=kth(root,x);printf("%d\n",tree[w].v);break;
        case 5:w=pre(root,x);printf("%d\n",tree[w].v);break;
        case 6:w=suf(root,x);printf("%d\n",tree[w].v);break;
        }
    }
    return 0;
}

建议学习新的平衡树可以用【bzoj3224】Tyvj 1728 普通平衡树 这题啊

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值