[算法]初探FHQ_treap算法与应用

写在前面

fhq-treap是最近几天学平衡树的时候恰巧遇到的,学习后深感fhq思想的厉害,于是便忍不住写了这篇文章。

我的实力水平不够,所以若是内容有差错或有疏漏的,请指出谢谢。

前置知识:二叉搜索树->平衡树(最好把treap学了)

算法简析

首先根据名字我们就知道了,fhq-treap相当于treap强化版。

Q:对于这个数据结构有什么用?

A:它可以完成单点修改,区间修改,单点查询,区间查询等,也就是说可以代替treapsplay(这里有些不严谨,但我就是用fhq treap代替splay用的)

我们都知道平衡树其实区别就在于它的核心操作平衡部分,对于fhq treap,它有两个核心部分:

1.split 英文是分裂的意思,它的作用就是将一颗树分成两颗树

2.Merge 合并,它的作用是将两棵树合并成一颗树

可能初看这两个操作,你完全想不到怎么用于平衡树,下面是分析。

 

关于下面的结构体内变量解释:

  1.lson:左子树的地址

  2.rson:右子树的地址

  3.size:以当前位置的根的树的大小

  4.fix:修正值,这是一个随机数,用于维护平衡

  5.val:权值

函数名解释

  1.Insert 插入

  2.Delete 删除

  3.update_size 更新当前位置为根的树的大小

1.split

常见分裂的方法一般有两种,一种是按照排名分裂,另一种是按照权值分裂。

本质上其实都是一致的,比方说对于一个序列

 

 

 我们需要将它在树中分成1~3与4~6两颗树

那么它在树中便是这样切开

 

 

 其中红色与粉色便是最终分裂出来的两棵树

可能这有些难理解所以还是结合代码自己好好想想

//这里是以排名为基准分裂的
inline void split(int r,int k,int &x,int &y) { if(!r) x = y = 0;//因为啥都没有所以无法分裂 else{ if(k <= fhq[fhq[r].lson].size) y = r,split(fhq[r].lson,k,x,fhq[r].lson); else x = r,split(fhq[r].rson,k - fhq[fhq[r].lson].size - 1,fhq[r].rson,y); update_size(r); } return ; }

2.Merge

那么对于两颗分裂的树,在分裂后肯定要将它们合并为新的树

维护平衡的操作也在这里

在treap中我们通过比较 fix 修正值来进行左旋右旋维护平衡

在fhq-treap中合并操作也是通过fix值维护平衡

首先我们知道分裂后得到的两棵树是左子树与右子树

重点:根据二叉搜索树的性质,左子树任何节点都小于右子树任何节点

也就是说,左子树的右子树(即图中以3为根的树)与右子树(即图中以4为根的树)也满足左子树与右子树性质(这句话很乱结合图多看看)

所以我们就可以合并这两颗树,即合并以3为根的树与以4为根的树,最后以这颗新的合并的树成为2为根的右子树(乱,多看图理解)

这就是合并的原理,另一种情况同理

 

 

 

inline int Merge(int x,int y)
{
    if(!x || !y) return x|y;//返回那个有子树的坐标
    else{
        if(fhq[x].fix > fhq[y].fix){
            fhq[x].rson = Merge(fhq[x].rson,y);
            update_size(x);
            return x; 
        }
        else{
            fhq[y].lson = Merge(x,fhq[y].lson);
            update_size(y);
            return y;
        }
    } 
}

于是乎,我们就知道这两个操作是如何实现的了

但是可能还不知道如何应用与修改等操作中

应用

我们可以用一个序列帮助理解

 

 

 

因为我懒得写代码,所以这里只提供思路,请另寻大佬们的代码

 

 假设我们想要删掉值为 4 的节点

我们可以先通过 Split 操作将树分为1~4(橙) 与 5~6(黄)两个子树

再通过一次 Split 操作将(橙)树分为1~3(蓝) 与 4(绿) 两个子树

 然后将蓝黄树合并就可以了

如果你看懂了,你就会明白fhq treap的魅力在哪里。

 

同理,对于区间删除,我们只需要改变分裂大小也可以分成三颗树,然后合并其中你留下的两颗就行了

 

而对于单点区间修改,在分裂为三颗树后,我们对于我们需要的树,根节点打下一个标记(加法,减法,乘法等等),在后来的分裂合并操作中,下传标记就好了。

练习

对于fhq treap的题,其实大部分的平衡树题都能用,这里就只放出三个

洛谷P3369 【模板】普通平衡树

洛谷P3391 【模板】文艺平衡树

洛谷P3960 列队

难度依次递进

 

发牢骚写在后面

已经是准高一了,明明退役还只有半年但还是又继续学oi了,希望自己能进步吧。

 

 

posted @ 2020-07-28 10:28  Happydaylhp  阅读(237)  评论(0编辑  收藏  举报