第四章数据结构 (4):可持久化数据结构、平衡树、AC自动机

CSP考完了再来处理这里的内容,只求前4题,CSP的风格应该不会考到这些吧o(╥﹏╥)o

一、可持久化数据结构

可持久化前提:本身的拓扑结构在操作过程中是不改变的

可持久化解决问题
可以存储数据结构的历史版本
核心思想:仅记录每一个版本与前一个版本不同的地方

Trie树的可持久化

假设有字符串cat、rat、cab、fry,则静态Trie树:
在这里插入图片描述

可持久化Trie树,图中绿色虚线相连的结点实质上是同一个结点:
在这里插入图片描述

// 插入操作

// 旧结点p,开一个新结点q
p = root[i -1], q = root[i] = ++ idx; 

// 检查p是否为空,如果是空的,则说明q是一个全新的点,否则q应该是p克隆过来的
if (p) tr[q] = tr[p];

// 更新当前结点新的儿子结点
tr[q][si] = ++ idx;

// 继续往下做,直到将当前单词插入完为止
p = tr[p][si], q = tr[q][si];

线段树的可持久化——主席树

CSP考完了再来听

1.1 最大异或和

ACwing 256

构建一个前缀和数组 S i S_i Si,其中 S 0 = 0 S 1 = A 1 S 2 = A 1 ∧ A 2 . . . S i = A 1 ∧ A 2 ∧ . . . ∧ A i \begin{aligned} &S_0 = 0\\ &S_1 = A_1\\ &S_2 = A_1 \land A_2\\ &...\\ &S_i = A_1 \land A_2 \land ... \land A_i\\ \end{aligned} S0=0S1=A1S2=A1A2...Si=A1A2...Ai选定一个位置 p p p,那么 A p ∧ . . . ∧ A n ∧ x = S p − 1 ∧ S n ∧ x A_p \land ... \land A_n \land x = S_{p-1} \land S_n \land x Ap...Anx=Sp1Snx又因为 S n ∧ x S_n \land x Snx是一个固定值,所以就要求在区间 [ L , R ] [L,R] [L,R]中找到某个位置 p p p,使得 S p − 1 ∧ S n ∧ x S_{p-1} \land S_n \land x Sp1Snx的值最大。

如果是从 [ 1 , R ] [1,R] [1,R]中选择某个位置 p p p,使得上式的值最大,这里可以使用可持久化的Trie树来存储每个历史版本的Trie树,如果查询 [ 1 , R ] [1,R] [1,R],只需要查询root[R]为根节点的这个版本的子树,这里面存的就是 [ 1 , R ] [1,R] [1,R]中的每一个数。

如果是从 [ L , R ] [L,R] [L,R]中选择某个位置 p p p,使得上式的值最大。相当于问左边子树中是否至少存在一个数,它的下标>= L,等价于左子树下标的最大值是否>= L。所以可以在Trie树中每个结点使用max_id记录当前子树中下标的最大值。

  • 对是否超过使用空间的估算:空间瓶颈在代码第13行的数组, M × 2 + M = M × 3 = 600000 × 25 × 3 = 1.5 × 1 0 7 × 3 = 4.5 × 1 0 7 M \times 2 + M = M \times 3 = 600000 \times 25 \times 3 = 1.5 \times 10^7 \times 3 = 4.5 \times 10^7 M×2+M=M×3=600000×25×3=1.5×107×3=4.5×107。那么这么大的数据需要 4.5 × 1 0 7 × 4 1 0 6 = 180 M \frac{4.5 \times 10^7 \times 4}{10^6} = 180M 1064.5×107×4=180M,其中数组是int4bite,分母除以1e6是将bite转换为兆M。这里加上数组 s [ N ] s[N] s[N]的空间 f 600000 × 4 1 0 7 f\frac{600000 \times 4}{10^7} f107600000×4是小于题目要求 256 M 256M 256M的,所以不会爆空间。
  • 因为Trie树是容易爆空间的,如果最后计算出爆了空间,可以使用最大空间250M来反推,即在空间大小限制250M下, 最多可以开多少个结点,就开对少个结点。
#include <iostream>
#include <algorithm>

using namespace std;

// 原始数据30w + 操作30w = 序列长度 60w
// Trie中每次操作最多建立24个结点(trie长度24),2^(24 + 根结点) = 2^25 > 1e7
// 一共添加60w次,每次增加25个新结点
const int N = 600010, M = N * 25;

int n, m;
int s[N];
int tr[M][2], max_id[M];
int root[N], idx;

// i为前缀和数组S下标,当前处理到第k位,上一个版本为p,最当前最新版本q
void insert(int i, int k, int p, int q) {
    if (k < 0) { // 处理完最后一位
        max_id[q] = i; // q就是叶子结点
        return;
    }
    int v = s[i] >> k & 1; // 当前这一位
    if (p) // p大于0表示,q是p的复制,将其信息复制过来
        tr[q][v ^ 1] = tr[p][v ^ 1];
    tr[q][v] = ++idx; // 给当当前这一位开一个新的点
    insert(i, k - 1, tr[p][v], tr[q][v]);
    max_id[q] = max(max_id[tr[q][0]], max_id[tr[q][1]]); // 更新max_id
}

// 从某个root开始,当前的值c,左边的限制L
int query(int root, int C, int L) {
    int p = root;
    for (int i = 23; i >= 0; i--) {
        int v = C >> i & 1;
        if (max_id[tr[p][v ^ 1]] >= L) 
            p = tr[p][v ^ 1];
        else p = tr[p][v];
    }

    return C ^ s[max_id[p]];
}

int main() {
    scanf("%d%d", &n, &m);

    max_id[0] = -1; // 根结点的max_id,因为前缀和里面s[0]也是一个合法的值,所以需要一个 <0 的数
    root[0] = ++idx;
    insert(0, 23, 0, root[0]);

    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        s[i] = s[i - 1] ^ x;
        root[i] = ++idx;
        insert(i, 23, root[i - 1], root[i]);
    }

    char op[2];
    int l, r, x;
    while (m--) {
        scanf("%s", op);
        if (*op == 'A') {
            scanf("%d", &x);
            n++;
            s[n] = s[n - 1] ^ x;
            root[n] = ++idx;
            insert(n, 23, root[n - 1], root[n]);
        } else {
            scanf("%d%d%d", &l, &r, &x);
            printf("%d\n", query(root[r - 1], s[n] ^ x, l - 1));
        }
    }

    return 0;
}

1.2 第K小数

CSP考完了再来听

二、平衡树 (Treap = Tree + Heap)

  • 二叉搜索树 (BST):
    • 当前结点的左子树中的任何一个结点的权值 < < < 当前结点的权值;
    • 当前结点的右子树中的任何一个结点的权值 > > > 当前结点的权值;
    • BST中一般不存在相同权值的结点,如果存在,则在该结点上使用一个count来记录该权值出现次数;
    • BST的中序遍历是一个从小到大有序序列;
    • 作用:动态维护一个有序序列
    • 常用操作:insert、delete、找前驱/后继、找最大\最小、求某个值的排名、求排名为k的数的值、比某个数小的最大值、比某个数大的最小值
  • 堆 (Heap),这里特指大根堆。

Treap核心思想:让BST尽可能变得随机。

Node{
	int l, r; // 左右儿子
	int key, val; // key值BST中排序的k,应该有序,val是堆中的val,应该大于左右儿子的val,即这个树要同时满足BST+堆
}tr[N];

CSP考完了再来听

2.1 普通平衡树

2.2 营业额统计

三、AC自动机

CSP考完了再来听

3.1 搜索关键词

3.2 单词

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值