FHQ Treap:不忘初心,方得始终!

Treap,它不像splay那样功能强大,在速度上也远不如AVL、RBT等平衡树,但是FHQ Treap的诞生却改变了这一切。FHQ Treap的核心操作是分裂与合并,这种操作方式使得它天生支持维护序列、可持久化等特性。它几乎可以实现splay的所有功能,尽管在速度上没有什么优势,但相对于其它平衡树来说代码较短且容易实现。

普通平衡树

#pragma GCC optimize(3,"Ofast","inline")

#include<bits/stdc++.h>

using namespace std;

const int INF=0x7fffffff;
const int N=2000010;

struct Node
{
   
    int l,r;
    int key,size;
    unsigned int val;
    
}tr[N];

mt19937 mt_rand(233);
int root,tot,rt1,rt2,rt3;
int New(int key)
{
   
    tr[++tot].key=key;
    tr[tot].val=mt_rand();
    tr[tot].size=1;
    return tot;
}

void pushup(int p)
{
   
    tr[p].size=tr[tr[p].l].size+tr[tr[p].r].size+1;
}
void split(int now,int k,int &x,int &y)
{
   
    if(!now)x=y=0;
    else{
   
        if(tr[now].key<=k)//按关键值分裂,并且分裂时BST性质和大根堆性质不会受到影响
            x=now,split(tr[now].r,k,tr[now].r,y);
        else y=now,split(tr[now].l,k,x,tr[now].l);
        pushup(now);
    }
}
int merge(int x,int y)//x树的key均小于等于y树是合并的基础,这可以保证合并时满足BST性质
{
   
    if(!x||!y)return x+y;
    if(tr[x].val>tr[y].val)//保证大根堆性质
    {
   
        tr[x].r=merge(tr[x].r,y);//将y挂在x身上,注意参数顺序不要搞反,不然就凉了
        pushup(x);
        return x;
    }
    else
    {
   
        tr[y].l=merge(x,tr[y].l);//将x挂在y身上
        pushup(y);
        return y;
    }
}

int kth(int rt,int rank)//求以rt为根的子树中的第K大数,它也是求前驱和后继的基础
{
   
    int now=rt;
    while(now)
    {
   
        if(tr[tr[now].l].size+1==rank)break;
        if(tr[tr[now].l].size>=rank)now=tr[now].l;
        else
        {
   
            rank-=tr[tr[now].l].size+1;
            now=tr[now].r;
        }
    }
    return now?tr[now].key:INF;//找不到就返回INF
}

void insert(int x)
{
   
    split(root,x,rt1,rt2);
    rt1=merge(rt1,New(x));
    root=merge(rt1,rt2);
}
void erase(int x)
{
   
    split(root,x,rt1,rt3);
    split(rt1,x-1,rt1,rt2);
    rt2=merge(tr[rt2].l,tr[rt2].r);
    root=merge(merge(rt1,rt2),rt3);
}

int getrank(int x)
{
   
    split(root,x-1,rt1,rt2);
    int ans=tr[rt1].size+1;
    root=merge(rt1,rt2);
    return ans;
}
int pre(int x)
{
   
    split(root,x-1,rt1,rt2);
    int ans=kth(rt1,tr[rt1].size);
    root=merge(rt1,rt2);
    return ans;
}
int nxt(int x)
{
   
    split(root,x,rt1,rt2)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值