平衡树——(不旋转的那种)——fhp heap——可持久化序列

一、什么是fhp treap,有什么用

  treap,即tree+heap,而且这个tree是BST

  简单的讲,treap是一棵树,而它有以下几个性质

       1、样子就是(或 几乎是)一颗完全二叉树

 

 

       2、它的节点的值满足BST——即: 左儿子 <= 根 <= 右儿子

       3、它的节点序号满足根堆,若令其满足大根堆——即: 根节点序号 > 左儿子、右儿子 ——而这里我们用一个随机的fix数组来维护(保证结构的随机性)

--------->fhp treap

  若是有旋treap,则我们通过旋转树的方式来保证树的平衡,

  而对于非旋treap,我们则通过 合并+拆分 来实现——那么,由于拆分和合并,所以每一颗子树内的顺序是不会变的,所以,我们可以拿来维护序列___

---------------------------->可持久化

  由于我们是合并+拆分,那么整棵树的大致结构就不会变,由此可以延伸出 持久化 的作用——要变的建立新节点,添加更改过后的节点并记录,复制不变的节点——这样,我们既有了新的一个版本,也保留了原来的版本,于是达到了持久化的目的

 

那么来看一道题——

二、例题

    #2782 可持久化序列【模板】

  描述

  您需要维护一个序列,其中需要提供以下操作:

  插入一个数到序列的第 t 版本使其成为序列的第 k项,这个数为 x ;

  删除序列的第 t 版本的第 k 项;

  查询序列的第 t 版本的第 k 项。

  第 0 个版本为空序列。修改操作不会影响被修改的版本,而总是产生一个新版本。

  输入

  第一行有一个正整数 n 表示操作的数量。

  接下来 n 行每行第一个正整数 opt 表示操作的类型,后面有 3 个整数 t,k,x 或 2 个整数 t,k 表示操作的参数。

  输出

  对于每个查询操作输出一行一个数,表示查询的结果。

样例输入
17
1 0 1 1
1 1 1 2
1 2 1 3
2 3 2
3 4 2
1 4 3 4
1 5 1 5
3 3 2
1 3 4 6
1 6 3 7
1 7 1 8
3 8 2
3 7 3
2 8 4
2 9 2
3 11 4
3 10 4

样例输出
1
2
3
1
6
4
样例

代码——

#include <bits/stdc++.h>
using namespace std;

#define lc(x) ch[x][0]
#define rc(x) ch[x][1]
#define N 300010
#define M (N * 50)

typedef pair<int, int> dat;            //代表分裂后两颗子树的根节点编号
int ch[M][2], val[M], siz[M], fix[M];  //val维护BST的性质,fix维护斜堆的性质
int cnt = 0, n, rt[N];                 //rt维护的是第t个版本的平衡树的根节点

inline int read() {
    int f = 1, k = 0;
    char c = getchar();
    while (c != '-' && (c < '0' || c > '9')) {
        c = getchar();
    }
    if (c == '-') {
        f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        k = (k << 3) + (k << 1) + (c ^ 48);
        c = getchar();
    }
    return f * k;
}

inline void copy(int a, int b) {  //复制一遍节点
    val[a] = val[b];
    siz[a] = siz[b];
    ch[a][0] = ch[b][0];
    ch[a][1] = ch[b][1];
    fix[a] = fix[b];
}

inline void pushup(int o) {  //和线段树的同理
    siz[o] = siz[lc(o)] + siz[rc(o)] + 1;
}

inline int newnode(int x = 0) {  //新建节点——持久化
    val[++cnt] = x;
    siz[cnt] = 1;
    ch[cnt][0] = ch[cnt][1] = 0;
    fix[cnt] = rand() % 5000;
    return cnt;
}

inline int merge(int a, int b) {  //合并:由于我们的维护,左右子树(a,b)已经满足了BST,然后我们根据
    if (!a || !b) {               //随机出来的fix来满足根节点的priority性质(决定谁做合并后的子树的根)
        return a + b;
    }
    int x = ++cnt;
    if (fix[a] < fix[b]) {
        copy(x, a);
        ch[x][1] = merge(ch[x][1], b);
    } else {
        copy(x, b);
        ch[x][0] = merge(a, ch[x][0]);
    }
    pushup(x);
    return x;
}

inline dat split(int o, int k) {  //拆分将以o为节点的树分裂,k就相当于是拆分出来的左子树的大小,
    if (!o) {                     //返回的是两颗子树的根节点编号
        return make_pair(0, 0);
    }               //上一个结点已经是叶子结点
    int x = ++cnt;  //建立新节点
    copy(x, o);
    dat t;
    if (k <= siz[lc(x)]) {
        t = split(lc(x), k);
        ch[x][0] = t.second;
        pushup(x);
        return make_pair(t.first, x);
    } else {
        t = split(rc(x), k - siz[lc(x)] - 1);
        ch[x][1] = t.first;
        pushup(x);
        return make_pair(x, t.second);
    }
}

inline int insert(int o, int k, int x) {
    dat t = split(o, k - 1);  //先把前k-1分裂出来
    int tmp = newnode(x);
    int ret = merge(merge(t.first, tmp), t.second);
    return ret;  //返回新版本根节点编号
}

inline int del(int o, int k) {
    dat a = split(o, k - 1);
    dat b = split(a.second, 1);
    return merge(a.first, b.second);
}

inline int f_k_th(int o, int k) {  //找第k大
    if (!o) return 0;
    if (k == siz[lc(o)] + 1) return val[o];  //当前子树根节点
    if (k <= siz[lc(o)]) return f_k_th(lc(o), k);
    return f_k_th(rc(o), k - siz[lc(o)] - 1);
}

int main() {
    int tot = 0;
    rt[0] = 0;
    n = read();

    for (int i = 1; i <= n; i++) {
        int op, t, k, x;
        op = read();
        t = read();
        k = read();

        if (op == 1) x = read();
        switch (op) {
            case 1: {
                rt[++tot] = insert(rt[t], k, x);
                break;
            }
            case 2: {
                rt[++tot] = del(rt[t], k);
                break;
            }
            case 3: {
                printf("%d\n", f_k_th(rt[t], k));
                break;
            }
        }
    }

    return 0;
}
View Code

 

posted @ 2020-11-14 16:05  everlasting_k  阅读(242)  评论(1)    收藏  举报
Live2D