首页 > 其他分享 >FHG无旋treap

FHG无旋treap

时间:2022-08-25 00:58:27浏览次数:48  
标签:sz val merge int 无旋 FHG tr treap now

FHG无旋treap能做大部分splay能完成的操作,而且代码比较短,思路比较splay来说也更加易懂一些,是性价比很高的数据结构,推荐入手,视频可以看b站Agoh大佬的视频,讲的很清晰,但是splay也是要学的,不是说学了FHGtreap就可以完全替代splay,splay的灵活度还是高于FHGtreap的。

前置知识:平衡树,动态开点

下面我们来学学FHG无旋treap的思路和具体如何实现!!

 

主要有两个函数实现,spilt(), merge()

首先是一棵树要维护的信息

struct Node{
    int l, r, val;
    int key; 
    // 还有具体题目中需要维护的信息
}
int root, idx;

动态开点函数

int Newnode(int val)
{//开点并初始化
    int u = ++ idx;
    tr[u].key = rand();// key用来维护大根堆(小根堆)的性质,随机值可以保证树的高度平均值是logn
    tr[u].val = val;
    return u;
}

按值分裂

//按值分裂,小于等于val的为x树,大于等于val的为y树
void spilt(int now, int val, int &x, int &y)
{
    if(!now) x = y = 0; 
    else
    {
        if(tr[u].val <= val)//如果根节点权值小于val,根节点和左子树分裂到x树,然后递归到右子树继续分裂
        {
            x = now;
            spilt(tr[now].r, val, tr[x].r, y);
        }
        else
        {//同上
            y = now;
            spilt(tr[now].l, val, x, tr[y].l);
        }
        pushup(now);//维护一下树的信息
    }
}

按树的大小分裂

//按树的大小分裂,分裂以后x树的大小为sz,其余为y树
void spilt(int now, int sz, int &x, int &y)
{
    if(!now) x = y = 0;
    else
    {
        if(tr[tr[u].l] < sz)
        {
            x = now;
            spilt(tr[now].r, sz - tr[tr[u].l].sz - 1, tr[x].r, y);
        }
        else 
        {
            y = now;
            spilt(tr[now].l, sz, x, tr[y].l);
        }
        pushup(now);
    }
}

merge(合并)

int merge(int x, int y)//将x,y树合并,返回根节点
{
    if(!x || !y) return x + y;
    else
    {
        if(tr[x].key >= tr[y].key) 
        // 维护大根堆的性质,如果x的key大于y的key,合并之后x为根节点,y是x的右儿子
        {
            tr[x].r = merge(tr[x].r, y);
            pushup(x);
            return x;
        }
        else
        {//同上
            tr[y].l = merge(x, tr[y].l);
            pushup(y);
            return y;
        }
    }
}

 

模板题:https://www.luogu.com.cn/problem/P3369

 

代码展示:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <set>
#include <map>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;


#define x first
#define y second


typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<PII, int> PIII;
typedef pair<LL, LL> PLL;
const int N = 100010, M = 50000, mod = 998244353, INF = 0x3f3f3f3f;


struct tree{
    int l, r;
    int key, val;
    int sz;
}tr[N];
int root, cnt;


int newNode(int val)
{
    tr[++ cnt].key = rand();
    tr[cnt].val = val;
    tr[cnt].sz = 1;
    return cnt;
}

void update(int now)
{
    tr[now].sz = tr[tr[now].l].sz + tr[tr[now].r].sz + 1;
}

void spilt(int now, int val, int &x, int &y)
{
    if(!now) x = y = 0;
    
    else
    {
        if(tr[now].val <= val)
        {
            x = now;
            spilt(tr[now].r, val, tr[now].r, y);
        }
        else 
        {
            y = now;
            spilt(tr[now].l, val, x, tr[now].l);
        }
        update(now);
    }
}

int merge(int x, int y)
{
    if(!x || !y) return x + y;
    if(tr[x].key > tr[y].key)
    {
        tr[x].r = merge(tr[x].r, y);
        update(x);
        return x;
    }
    else
    {
        tr[y].l = merge(x, tr[y].l );
        update(y);
        return y;
    }
}

int x, y, z;
void insert(int val)
{
    spilt(root, val, x, y);
    root = merge(merge(x, newNode(val)), y);
}

void remove(int val)
{
    spilt(root, val, x, z);
    spilt(x, val - 1, x, y);
    y = merge(tr[y].l, tr[y].r);
    root = merge(merge(x, y), z);
}

void get_rank(int val)
{
    spilt(root, val - 1, x, y);
    printf("%d\n", tr[x].sz + 1);
    root = merge(x, y);
}

void get_num(int rank)
{
    int now = root;
    while(now)
    {
        if(tr[tr[now].l].sz + 1 == rank) break;
        else if(tr[tr[now].l].sz >= rank) now = tr[now].l;
        else
        {
            rank -= tr[tr[now].l].sz + 1;
            now = tr[now].r;
        }
    }
    printf("%d\n", tr[now].val);
}

void get_pre(int val)
{
    spilt(root, val - 1, x, y);
    int now = x;
    while(tr[now].r) now = tr[now].r;
    printf("%d\n", tr[now].val);
    root = merge(x, y);
}

void get_next(int val)
{
    spilt(root, val, x, y);
    int now = y;
    while(tr[now].l) now = tr[now].l;
    printf("%d\n", tr[now].val);
    root = merge(x, y);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++ )
    {
        int op, x;
        scanf("%d %d", &op, &x);
        if(op == 1) insert(x);
        else if(op == 2) remove(x);
        else if(op == 3) get_rank(x);
        else if(op == 4) get_num(x);
        else if(op == 5) get_pre(x);
        else get_next(x);
    }
    return 0;
}

 

标签:sz,val,merge,int,无旋,FHG,tr,treap,now
From: https://www.cnblogs.com/jay1573/p/16622848.html

相关文章