模板 - 可持久化无旋Treap

空间消耗非常玄学,有多大开多大就完事了。其实是因为单次操作可能会有数次Merge和Split操作,按照下面的版本的话Merge和Split都进行复制,所以一次操作可能复制了4个版本。
四个函数式查询,然后Merge的时候拷贝对应的xy子树,Split的时候拷贝p树。事实上,Merge和Split总是成对出现,只需要在其中喜欢的一个进行可持久化(复制节点)就可以了,比较推荐在Split的时候复制节点。这样单次操作大概复制2个版本。

#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 = 30000000 + 5;
int val[MAXN], ch[MAXN][2], rnd[MAXN], siz[MAXN], tot, root[MAXN];

void Init() {
    tot = 0;
    memset(root,0,sizeof(root));
}

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

int CopyNode(int p) {
    ++tot;
    ch[tot][0] = ch[p][0];
    ch[tot][1] = ch[p][1];
    val[tot] = val[p];
    rnd[tot] = rnd[p];
    siz[tot] = siz[p];
    return tot;
}

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 = CopyNode(p);
        SplitValue(ls(y), v, x, ls(y));
        PushUp(y);
    } else {
        x = CopyNode(p);
        SplitValue(rs(x), v, rs(x), 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]) {
        int p = CopyNode(x);
        rs(p) = Merge(rs(p), y);
        PushUp(p);
        return p;
    } else {
        int p = CopyNode(y);
        ls(p) = Merge(x, ls(p));
        PushUp(p);
        return p;
    }
}

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 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;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    scanf("%d", &n);
    Init();
    for(int i = 1; i <= n; ++i) {
        int v,op, x;
        scanf("%d%d%d",&v, &op, &x);
        root[i]=root[v];
        switch(op) {
            case 1:
                Insert(root[i], x);
                break;
            case 2:
                Remove(root[i], x);
                break;
            case 3:
                printf("%d\n", GetRank2(root[i], x));
                break;
            case 4:
                printf("%d\n", GetValue2(root[i], x));
                break;
            case 5:
                printf("%d\n", GetPrev2(root[i], x));
                break;
            case 6:
                printf("%d\n", GetNext2(root[i], x));
                break;
        }
    }
    return 0;
}
#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 = 20000000 + 5;
int val[MAXN], ch[MAXN][2], rnd[MAXN], siz[MAXN], tot, root[MAXN];

void Init() {
    tot = 0;
    memset(root,0,sizeof(root));
}

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

int CopyNode(int p) {
    ++tot;
    ch[tot][0] = ch[p][0];
    ch[tot][1] = ch[p][1];
    val[tot] = val[p];
    rnd[tot] = rnd[p];
    siz[tot] = siz[p];
    return tot;
}

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 = CopyNode(p);
        SplitValue(ls(y), v, x, ls(y));
        PushUp(y);
    } else {
        x = CopyNode(p);
        SplitValue(rs(x), v, rs(x), 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]) {
        //int p = CopyNode(x);
        int p=x;
        rs(p) = Merge(rs(p), y);
        PushUp(p);
        return p;
    } else {
        int p=y;
        //int p = CopyNode(y);
        ls(p) = Merge(x, ls(p));
        PushUp(p);
        return p;
    }
}

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 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;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    scanf("%d", &n);
    Init();
    for(int i = 1; i <= n; ++i) {
        int v,op, x;
        scanf("%d%d%d",&v, &op, &x);
        root[i]=root[v];
        switch(op) {
            case 1:
                Insert(root[i], x);
                break;
            case 2:
                Remove(root[i], x);
                break;
            case 3:
                printf("%d\n", GetRank2(root[i], x));
                break;
            case 4:
                printf("%d\n", GetValue2(root[i], x));
                break;
            case 5:
                printf("%d\n", GetPrev2(root[i], x));
                break;
            case 6:
                printf("%d\n", GetNext2(root[i], x));
                break;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Yinku/p/11330360.html

时间: 2024-11-13 09:24:45

模板 - 可持久化无旋Treap的相关文章

模板 - 数据结构 - 无旋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 Pu

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

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

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

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

[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<

[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>

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

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

【模板】无旋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))

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) {

[BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MB Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可能把他们的工资扣除一个相同的量.我真不知道除了调工资他还做什么其它事情.工资的频繁调