首页 > 其他分享 >fhq_treap

fhq_treap

时间:2023-02-04 11:56:59浏览次数:58  
标签:val merge int treap now fhq size

FHQ treap

参考: 链接

Treap:

优点: 码量小 好写 核心代码是复读机

好理解 支持操作多

缺点: 常数大了点

维护平衡的奇怪操作:

Treap: 旋转

FHQ Treap: 分裂 合并

节点信息

  1. 左右子树编号
  2. 索引
  3. 子树大小
struct node
{
    int l, r;
    int val, key;
    int size;
}fhq[N];
int cnt, root;
//建立新节点
inline int New(int val)
{
    fhq[++ cnt].val = val;
    fhq[cnt].key = rand();
    fhq[cnt].size = 1;
    return cnt;
}

分裂(split)

有2种:按值分裂,按大小分裂

按值分裂

把树拆成两棵树,拆出来的一棵树的值全部小于等于给定的值,另外一部分的值全部大于给定的值

按大小分裂

把树拆成两棵树,拆出来的一棵树的大小等于给定的大小,另外一部分在另一颗树里

(一般当平衡树时用按值分裂)

(维护区间信息的时候按大小分裂, 最经典的就是文艺平衡树)
2v4Mz.png
分裂->
2vDtw.png

inline void update(int now)
{
    fhq[now].size = fhq[fhq[now].l].size + fhq[fhq[now].r].size + 1;
}
void split(int now, int val, int &x, int &y)
{
    if(!now) x = y = 0;
    else
    {
        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);
        }
        update(now);
    }
}

合并

把两棵树x, y合并成一棵树(x树上的所有值都小于等于y树上的所有值, 并且新合并出来的树满足treap的性质)
2vDtw.png

合并->

2v4Mz.png

int merge(int x, int y)
{
    if(!x || !y) return x + y;
    if(fhq[x].key > fhq[y].key) // < > <= >=都可以
    {
        fhq[x].r = merge(fhq[x].r, y);
        update(x);
        return x;
    }
    else
    {
        fhq[y].l = merge(x, fhq[y].l);
        update(y);
        return y;
    }
}

插入

设插入的值为val

  1. 按值val把树分裂成x, y
  2. 合并x, 新节点, y
int x, y, z;
inline void insert(int val)
{
    split(root, val, x, y);
    root = merge(merge(x, New(val)), y);
}

删除

  1. 按照值val把树分为x, z
  2. 再按值val-1把x分为x和y
  3. y树上值全部等于val, 去掉它的根节点:让y等于合并y的左子树和右子树
  4. 合并x, y, z
inline void del(int val)
{
    split(root, val, x, z);
    split(x, val - 1, x, y);
    y = merge(fhq[y].l, fhq[y].r);
    root = merge(merge(x, y), z);
}

查询排名

  1. 按值val-1分裂成x, y
  2. x的大小+1就是val的排名
  3. 把x, y合并
inline int getrank(int val)
{
    split(root, val - 1, x, y);
    int rank = fhq[x].size;
    root = merge(x, y);
    return rank + 1;
}

查询排名的值

inline int getsum(int rank)
{
    int now = root;
    while(now)
    {
        if(fhq[fhq.l].size + 1 == rank)
            break;
        else if(fhq[fhq[now].l].size >= rank)
            now = fhq[now].l;
        else
        {
            rank -= fhq[fhq[now].l].size + 1;
            now = fhq[now].r;
        }
    }
   return fhq[now].val;
}

前驱/后继

前驱: 按值val-1分裂成x, y, x里面最右的数就是val的前驱

后继: 按值val分裂成x, y, 则y里面最左的数就是val的后继

inline int pre(int val)
{
    split(root, val - 1, x, y);
    int now = x;
    while(fhq[now].r)
        now = fhq[now].r;
    int res = fhq[now].val;
    root = merge(x, y);
    return res;
}
inline int nxt(int val)
{
    split(root, val, x, y);
    while(fhq[now].l)
        now = fhq[now].l;
    int res = fhq[now].val;
    root = merge(x, y);
    return res;
}

不储存索引的fhq treap

只有在merge函数才有维护随机的操作

把merge操作里面改为随机的数据也可以

fhq treap的区间操作

P3391 文艺平衡树
链表\(O(n^2)\)
Splay或fhq treap\(O(nlogn)\)
实现区间操作:
设要操作的区间为[l, r], 我们就把这一段split出来操作然后合并回去
具体步骤:

  1. 把fhq treap按大小l-1拆分成x, y
  2. 把y按大小r-l+1拆分成y和z
  3. y树就是要操作的区间的平衡树
  4. 合并回去xyz

解决文艺平衡树

懒标记: 当我们想对一个区间进行翻转, 就对这个区间维护懒标记: 如果原来没有, 就加上; 如果原来有, 那就去掉
别忘了写懒标记pushdown操作, 如果当前节点左右子树有被更改的风险那就下传

struct node
{
    int l, r;
    int val, key;
    int size;
    bool reverse;
}fhq[N];
int cnt, root;
inline int New(int val)
{
    fhq[++ cnt].val = val;
    fhq[cnt].key = rand();
    fhq[cnt].size = 1;
    return cnt;
}
inline void update(int now)
{
    fhq[now].size = fhq[fhq[l]].size + fhq[fhq[now].r].size + 1;
}
inline void pushdown(int now)
{
    swap(fhq[now].l, fhq[now].r);
    fhq[fhq[now].l].reverse ^= 1;
    fhq[fhq[now].r].reverse ^= 1;
    fhq[now].reverse = false;
}
void split(int now, int siz, int &x, int &y)
{
    if(!now) x = y = 0;
    else
    {
        if(fhq[now].reverse) pushdown(now);
        if(fhq[fhq[now].l].size < siz)
        {
            x = now;
            split(fhq[now].r, siz - fhq[fhq[now].l].size - 1, fhq[now].r, y);
        }
        else
        {
            y = now;
            split(fhq[now].r, siz, x, fhq[now].l)
        }
        update(now);
    }
}
int merge(int x, int y)
{ 
    if(!x || !y) return x + y;
    if(fhq[x].key < fhq[y].key)
    {
        if(fhq[x].reverse) pushdown(x);
        fhq[x].r = merge(fhq[x].r, y);
        update(x);
        return x;
    }
    else
    {
        if(fhq[y].reverse) pushdown(y);
        fhq[y].l = merge(x, fhq[y].l);
        update(y);
        return y;
    }
}
void reverse(int l, int r)
{
    int x, y, z;
    split(root, l - 1, x, y);
    split(y, r - l + 1, y, z);
    fhq[y].reverse ^= 1;
    root = merge(merge(x, y), z);
}
void ldr(int now)
{
    if(!now) return;
    if(fhq[now].reverse) pushdown(now);
    ldr(fhq[now].l);
    printf("%d ", fhq[now].val);
    ldr(fhq[now].r);
}

标签:val,merge,int,treap,now,fhq,size
From: https://www.cnblogs.com/crimsonawa/p/17091215.html

相关文章

  • BZOJ 3224 普通平衡树 (BST+Treap)
    题目描述:您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:插入数值x。删除数值x(若有多个相同的数,应只删除一个)。查询数值x的排名(若有多个相同的数,应......
  • Treap 平衡二叉查找树
    【基本概念】Treap=Tree+Heap。Tree是指二叉搜索树,而Heap指的是二叉堆,一般是最小堆。Treap需要维护两值,一个是二叉搜索树中的键值(key),另一个是最小堆中的优先级(aux)。Treap是......
  • POJ2761 Feed the dogs(Treap)
    DescriptionWindlovesprettydogsverymuch,andshehasnpetdogs.SoJiajiahastofeedthedogseverydayforWind.JiajialovesWind,butnotthedogs,......
  • BZOJ1503 郁闷的出纳员 (Treap)
    DescriptionOIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们......
  • 学习笔记:二叉平衡树之 fhp-treap
    问题背景:你需要维护一个整数集合,可以满足一下几种操作:插入一个整数xx。删除一个整数xx(若有多个相同的数,只删除一个)。查询整数xx的排名(排名定义为比当前数小......
  • FHQ-treap 学习笔记
    FHQ-Treap学习这种平衡树不需要了解treap,据说treap和splay能干的事情他也能干。update:2023.1.12以前写的博客看起来太仓促了,修改了一下。前置芝士二叉搜索树的性......
  • fhqTreap学习笔记/做题记录
    \(\rmfhqTreap\)学习笔记&做题记录发大电部分我是\(\rmfhqTreap\)批众所周知,\(\rmfhqTreap\)可以部分(或者完全?)替代splay的区间功能,而且写起来又方便,所以去tm的s......
  • 「Note」闲话 2022.12.30(《浅谈Splay与Treap的性质及其应用》学习笔记)
    屎一样的一年还有两天就过去了呢。感觉都阳了一周了还是没有回复到正常状态,真的挺讨厌的。今天随便找了篇论文假学习了一会儿。由于懒,所以大量内容属摘抄。平衡树的fin......
  • 【学习笔记】(模板复习)FHQ平衡树
    对应模板:P3369【模板】普通平衡树点击查看代码#include<bits/stdc++.h>usingnamespacestd;inlineintrd(){ intf=1,j=0; charw=getchar(); while(w>'9'||w<'......
  • FHQ-Treap
    FHQ-Treap依赖分裂合并的tree+heap(听起来像ODT)核心操作:分裂:一种是按权值分裂,一种是按排名分裂根据粉兔的博客,发现权值操作都可以通过rank转化为排名于是乎只打排名......