fhq treap入门

本文介绍了fhq-treap数据结构,它结合了二叉堆和二叉搜索树,解决了二叉搜索树退化的问题,提供线性时间复杂度的操作。文章详细讲解了treap的原理、无旋特性、split和merge操作,并给出了三个模板题目,展示了fhq-treap在平衡树、区间序列维护和线段树问题上的应用。
摘要由CSDN通过智能技术生成

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述

一.前言

这个数据结构早有耳闻.只是一直没学.跟着AgOH学了一波.发现很简单.

二.原理

二叉搜索树之所以不够优秀,是因为存在一些数据能够将二叉搜索树退化成一条链.从而导致平方级的复杂度.那么对于这个缺陷,大佬们想出了很多方法去解决,衍生出了①替罪羊树②有旋/无旋Treap③splay.今天我入门学习的就是无旋treap.

Treap之所以能够克服二叉搜索树的缺陷,主要因为它以随机的方式构造二叉搜索树.使得毒瘤数据失效.具体就是将二叉堆和二叉搜索树结合起来.而无旋treap就不需要旋转操作.直接split+merge搞就可以了过程非常像玩拼图.

split有两种方式:按值分裂和按大小分裂.
1.将树分裂成两个部分,左部符合所有值小于等于val,右部符合所有值大于val.
2.将树分裂成两个部分,左部符合子树大小恰好等于val,右部符合大小为补集.

merge的过程很像线段树合并操作.


三.具体实现

说实话搞懂split操作和merge操作,基本就搞懂fhq-treap了.

大概结构:

1.每个节点需要存储:

struct Node
{
   
	// 左右儿子,该点的值,该点的优先级,该子树大小.
    int l , r , val , key , sz;
}fhq[maxn];

2.新建节点操作:

int newnode (int val){
   
    fhq[++cnt].val = val;
    fhq[cnt].key = rnd(); // 复杂度的保证
    fhq[cnt].sz = 1;
    return cnt;
}

3.在split/merge后更新节点信息:

void pushup (int x){
   
    fhq[x].sz = fhq[fhq[x].l].sz + fhq[fhq[x].r].sz + 1;
}

4.分裂操作:

//注:当前节点在now,以 val为界限分成两部分.左边的父亲节点是x.右边的父亲节点是y.
void split (int now , int val , int &x , int &y)
{
   
    if (!now){
   
        x = y = 0;
        return ;
    }
    // 代表根和左子树属于集合x.右子树尚未确定,需要继续抽离.
    if (fhq[now].val <= val){
   
        x = now;
        split(fhq[now].r , val , fhq[now].r , y);
    }else {
   // 反之一样.
        y = now;
        split(fhq[now].l , val , x , fhq[now].l);
    }
    pushup(now);
}

5.合并操作:

//注:将子树x和子树y合并,返回根节点.
// 有个前提条件:子树x的值全严格小于子树y的值,这样才能保证它在合并后还是颗二叉搜索树.
int mer (int x , int y)
{
   
	// 任意一个子树为空,返回另一个.两个都为空,返回空.
    if (!x || !y) return x + y;
    // 它同时又是一颗二叉堆,满足优先级特点.
    if (fhq[x].key > fhq[y].key){
   
        // x既要作为根,又因为前提,所以y要在x的右下方.
        fhq[x].r = mer(fhq[x].r , y);
        pushup(x);
        return x;
    }
    // 反之一样.
    fhq[y].l = mer(x , fhq[y].l);
    pushup(y);
    return y;
}

四.模板题目

4.1.洛谷P3369:普通平衡树

题目地址

fhqTreap可以实现所有其他平衡树能实现的效果.

1.插入数
2.删除 x 数(若有多个相同的数,因只删除一个)
3.查询 x 数的排名(排名定义为比当前数小的数的个数 +1 )
4.查询排名为 x 的数
5.求 x 的前驱(前驱定义为小于 x,且最大的数)
6.求 x 的后继(后继定义为大于 x,且最小的数)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
struct Node
{
   
    int l , r , val , key , sz;
}fhq[maxn];
int cnt , rt;
mt19937 rnd(233);
int newnode (int val){
   
    fhq[++cnt].val = val;
    fhq[cnt].key = rnd();
    fhq[cnt].sz = 1;
    return cnt;
}
void pushup (int x){
   
    fhq[x].sz = fhq[fhq[x].l].sz + fhq[fhq[x].r].sz + 1;
}
<
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值