模板 - 数据结构 - 无旋Treap / FHQ Treap

普通平衡树:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls(p) ch[p][0]
#define rs(p) ch[p][1]

const int MAXN = 100000 + 5;
int val[MAXN], ch[MAXN][2], rnd[MAXN], siz[MAXN], tot, root;

void Init() {
    tot = root = 0;
}

void PushUp(int p) {
    siz[p] = siz[ls(p)] + siz[rs(p)] + 1;
}

void SplitValue(int p, int v, int &x, int &y) {
    if(!p) {
        x = y = 0;
        return;
    }
    if(v < val[p]) {
        y = p;
        SplitValue(ls(p), v, x, ls(p));
        PushUp(y);
    } else {
        x = p;
        SplitValue(rs(p), v, rs(p), y);
        PushUp(x);
    }
}

void SplitRank(int p, int rk, int &x, int &y) {
    if(!p) {
        x = y = 0;
        return;
    }
    if(rk <= siz[ls(p)]) {
        y = p;
        SplitRank(ls(p), rk, x, ls(p));
        PushUp(y);
    } else {
        x = p;
        SplitRank(rs(p), rk - siz[ls(p)] - 1, rs(p), y);
        PushUp(x);
    }
}

int Merge(int x, int y) {
    if(!x || !y)
        return x | y;
    if(rnd[x] < rnd[y]) {
        rs(x) = Merge(rs(x), y);
        PushUp(x);
        return x;
    } else {
        ls(y) = Merge(x, ls(y));
        PushUp(y);
        return y;
    }
}

int NewNode(int v) {
    ++tot;
    ch[tot][0] = ch[tot][1] = 0;
    val[tot] = v, rnd[tot] = rand();
    siz[tot] = 1;
    return tot;
}

void Insert(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v, x, y);
    root = Merge(Merge(x, NewNode(v)), y);
}

void Remove(int &root, int v) {
    int x = 0, y = 0, z = 0;
    SplitValue(root, v, x, z);
    SplitValue(x, v - 1, x, y);
    y = Merge(ls(y), rs(y));
    root = Merge(Merge(x, y), z);
}

int GetRank(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v - 1, x, y);
    int rk = siz[x] + 1;
    root = Merge(x, y);
    return rk;
}

int GetValue(int &root, int rk) {
    int x = 0, y = 0, z = 0;
    SplitRank(root, rk, x, z);
    SplitRank(x, rk - 1, x, y);
    int v = val[y];
    root = Merge(Merge(x, y), z);
    return v;
}

int GetPrev(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v - 1, x, y);
    int prev = GetValue(x, siz[x]);
    root = Merge(x, y);
    return prev;
}

int GetNext(int &root, int v) {
    int x = 0, y = 0;
    SplitValue(root, v, x, y);
    int next = GetValue(y, 1);
    root = Merge(x, y);
    return next;
}

int main() {
    int n;
    scanf("%d", &n);
    Init();
    for(int i = 1; i <= n; ++i) {
        int op, x;
        scanf("%d%d", &op, &x);
        switch(op) {
            case 1:
                Insert(root, x);
                break;
            case 2:
                Remove(root, x);
                break;
            case 3:
                printf("%d\n", GetRank(root, x));
                break;
            case 4:
                printf("%d\n", GetValue(root, x));
                break;
            case 5:
                printf("%d\n", GetPrev(root, x));
                break;
            case 6:
                printf("%d\n", GetNext(root, x));
                break;
        }
    }
    return 0;
}

O(n)建树与回收:

//O(n)建树,返回新树的根
int st[MAXN], stop;
char buf[MAXN];
inline int Build(int n) {
    stop = 0;
    for(int i = 0; i < n; ++i) {
        int tmp = NewNode(buf[i]), last = 0;
        while(stop && rnd[st[stop]] > rnd[tmp]) {
            last = st[stop];
            PushUp(last);
            st[stop--] = 0;
        }
        if(stop)
            rs(st[stop]) = tmp;
        ls(tmp) = last;
        st[++stop] = tmp;
    }
    while(stop)
        PushUp(st[stop--]);
    return st[1];
}

//O(n)回收整棵树
inline void UnBuild(int p) {
    if(!p)
        return;
    UnBuild(ls(p));
    UnBuild(rs(p));
    RecBin.push(p);
}

非递归查询:

int GetRank2(int p, int v) {
    int rk = 1;
    while(p) {
        if(v < val[p])
            p = ls(p);
        else if(v == val[p])
            p = ls(p);
        else {
            rk += siz[ls(p)] + 1;
            p = rs(p);
        }
    }
    return rk;
}

int GetValue2(int p, int rk) {
    while(p) {
        if(rk <= siz[ls(p)])
            p = ls(p);
        else if(rk == siz[ls(p)] + 1)
            return val[p];
        else {
            rk -= siz[ls(p)] + 1;
            p = rs(p);
        }
    }
}

int GetPrev2(int p, int v) {
    int prev;
    while(p) {
        if(v <= val[p])
            p = ls(p);
        else {
            prev = val[p];
            p = rs(p);
        }
    }
    return prev;
}

int GetNext2(int p, int v) {
    int next;
    while(p) {
        if(v < val[p]) {
            next = val[p];
            p = ls(p);
        } else
            p = rs(p);
    }
    return next;
}

无旋Treap维护序列:

操作1翻转序列[L,R],操作2查询pos位置的字符。

#define ls(p) ch[p][0]
#define rs(p) ch[p][1]

const int MAXN = 1000000 + 5;
char val[MAXN];
int ch[MAXN][2], rnd[MAXN], siz[MAXN], tot, root;
bool rev[MAXN];

void Init() {
    tot = root = 0;
}

void PushUp(int p) {
    siz[p] = siz[ls(p)] + siz[rs(p)] + 1;
}

void PushDown(int p) {
    if(rev[p]) {
        swap(ls(p), rs(p));
        rev[ls(p)] ^= 1;
        rev[rs(p)] ^= 1;
        rev[p] = 0;
    }
}

void SplitRank(int p, int rk, int &x, int &y) {
    if(!p) {
        x = y = 0;
        return;
    }
    PushDown(p);
    if(rk <= siz[ls(p)]) {
        y = p;
        SplitRank(ls(p), rk, x, ls(p));
        PushUp(y);
    } else {
        x = p;
        SplitRank(rs(p), rk - siz[ls(p)] - 1, rs(p), y);
        PushUp(x);
    }
}

int Merge(int x, int y) {
    if(!x || !y)
        return x | y;
    if(rnd[x] < rnd[y]) {
        PushDown(x);
        rs(x) = Merge(rs(x), y);
        PushUp(x);
        return x;
    } else {
        PushDown(y);
        ls(y) = Merge(x, ls(y));
        PushUp(y);
        return y;
    }
}

int NewNode(int v) {
    ++tot;
    ch[tot][0] = ch[tot][1] = 0;
    val[tot] = v, rnd[tot] = rand();
    siz[tot] = 1;
    return tot;
}

void ReverseLR(int l, int r) {
    int x, y, z;
    SplitRank(root, l - 1, x, y);
    SplitRank(y, r + 1 - l, y, z);
    PushDown(y);
    rev[y] ^= 1;
    PushUp(y);
    root = Merge(Merge(x, y), z);
}

int ValuePos(int pos) {
    int x, y, z;
    SplitRank(root, pos - 1, x, z);
    SplitRank(z, 1, y, z);
    int ret = val[y];
    root = Merge(x, Merge(y, z));
    return ret;
}

需要搭配快读和线性建树才能卡过去。

原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12536406.html

时间: 2024-08-29 18:50:19

模板 - 数据结构 - 无旋Treap / FHQ Treap的相关文章

【模板】无旋Treap(FHQ)

如题,这是一个模板... 1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <cctype> 6 7 inline void read(int & x) 8 { 9 x = 0; 10 int k = 1; 11 char c = getchar(); 12 while (!isdigit(c))

可持久化Treap(fhq Treap,非旋转式Treap)学习(未完待续)

简介: Treap,一种表现优异的BST 优势: 其较于AVL.红黑树实现简单,浅显易懂 较于Splay常数小,通常用于树套BST表现远远优于Splay 或许有人想说SBT,SBT我没有实现过,据说比较快 但是SBT.Splay以及旋转版Treap等BST都不可以比较方便地实现‘可持久化操作 Treap=Tree+Heap Treap是一颗同时拥有二叉搜索树和堆性质的一颗二叉树 Treap有两个关键字,在这里定义为: 1.key,满足二叉搜索树性质,即中序遍历按照key值有序 2.fix,满足堆

Luogu 1177 - 【模板】快速排序 - [快速排序][归并排序][无旋Treap]

题目链接:https://www.luogu.org/problemnew/show/P1177 题意:输入 $n$ 以及后续 $n$ 个整数,让你将这 $n$ 个整数从小到大排序输出. 归并排序(用时: 121ms / 内存: 1568KB): #include<bits/stdc++.h> using namespace std; const int maxn=100000+5; int n,a[maxn],t[maxn]; void Merge(int l,int m,int r) {

[BZOJ3223]文艺平衡树 无旋Treap

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2--n-1,n)  m表示翻转操作次数接下来m行每行两个数[l,r] 数据保证 1<=l<

[您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我们还是用rand()来实现平衡 而无旋treap与treap不同的地方,也是其核心,就是它不旋转用两个新的核心函数:merge函数(合并两棵子树)和split函数(分裂出某棵树的前k个节点,并且作为一棵树返回) 首先看merge函数,它是一个递归实现的过程,先看代码: 1 Treap *merge(

[BZOJ1588][HNOI2002]营业额统计 无旋Treap

[HNOI2002]营业额统计 时间限制: 5 Sec  内存限制: 162 MB 题目描述 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题.经济管理学上定

【算法学习】Fhq-Treap(无旋Treap)

Treap--大名鼎鼎的随机二叉查找树,以优异的性能和简单的实现在OIer们中广泛流传. 这篇blog介绍一种不需要旋转操作来维护的Treap,即无旋Treap,也称Fhq-Treap. 它的巧妙之处在于只需要分离和合并两种基本操作,就能实现任意的平衡树常用修改操作. 而不需要旋转的特性也使编写代码时不需要考虑多种情况和复杂的父亲儿子关系的更新,同时降低了时间复杂度. 此外,它还可以方便地支持可持久化,实在是功能强大. 接下来系统性地介绍一下无旋Treap的原理和实现,最后讲解一下应用和例题.

[Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223 平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护的标准,而处理区间问题时,维护平衡树的应该是每个位置的下标,所以平衡树中序遍历时应该是当前区间的样子.例如: {1 2 3 4 5}翻转区间1 3,则中序遍历应该输出{3,2,1,4,5}. 提供splay和无旋Treap的做法. splay做法: 1 #include<bits/stdc++.h>

FHQ Treap小结(神级数据结构!)

首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右左右右的旋转之类的, 思路比较好理解,但是 代码量........ 一看就头大,, 然后,在洛谷翻题解的时候无意间看到了远航之曲发的一篇非常短小精悍的题解, 于是就学了一下 FHQ Treap 这个东西的学名应该是叫做fhq treap,应该是treap的强化版. 整个数据结构中只有两个操作: 1.