可持久化Trie树初步

可持久化Trie树和可持久化线段树很像,依次插入信息,通过减法来进行历史版本查询。

2015年11月12日

  bzoj3261 最大异或和

    我们需要计算 a[p] xor a[p+1] xor ... xor a[N] xor x ,设 sum[i] 表示 a[1] xor a[2] xor ... xor a[i] 的值,因为异或满足区间减法,所以求上一个式子等于求 sum[n] xor sum[p - 1] xor x,进一步,sum[n] xor x 为定值,所以需要找到二进制位上尽量不匹配的,由此需要使用Trie树。

    同时题目中有区间限制,所以我们需要一个可持久化的数据结构。

    1) 顺次将sum[i]插入到可持久化Trie树中。注意 : 我们需要让数位对齐,否则高位低位会错位,所以需要在每一个数的前面加上适当的0以使他们数位相等。

    插入时,可以采取递归的方式,用 >> 来确定这一位是多少,把没有改变的那一边链向历史版本。注意 : 在递归时,若采取d--(此处见代码)的方式,因为一个节点的左右儿子不是在同一个递归中构造完成,所以判断 d < 0  ---> break; 需要放在新建节点之后。

    2) 对于查询时,从根节点开始,同样采用d--的方式,逐位确定,如果 x 的这一位为 p ,那么我们查询Sum[son[l][p ^ 1]] - Sum[son[r][p ^ 1],Sum为节点上有多少的值,如若 表达式 > 0 那么我们就像 p ^ 1 的方向行走,同时 答案加上 1 << d 因为这一位被我们错开了,否则只好向 p 的方向行走, 不加上 1 << d。

    3) 因为我们要计算的是 sum[p - 1] xor sum[n] xor[x] 的值,所以对于给定的p的限制区间,我们必须把区间减一,再把左端点减一后查询,这里有一个小技巧 : 首先插入一个 0 的值到可持久化Trie树中,以作为第一个节点,对于后面的读入 比如说(l, r) 直接查询 (l - 1, r) 即可,因为已经事先减一了。

    4) 对于空间的问题,因为一条链最多有 floor(log(1e7)) + 1 的长度,又因为 n <= 300000, m <= 300000,有可能所有的option均为A,所以 (Maxn + Maxm) * (floor(log(1e7)) + 1)

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (int i = a; i <= b; i++)
 3 #define REP(i, a, b) for (int i = a; i < b; i++)
 4 #define drep(i, a, b) for (int i = a; i >= b; i--)
 5 #define pb push_back
 6 #define mp make_pair
 7 #define xx first
 8 #define yy second
 9 using namespace std;
10 typedef long long i64;
11 typedef pair<int, int> pii;
12 const int inf = ~0U >> 1;
13 const i64 INF = ~0ULL >> 1;
14 //*****************************
15 const int maxn = 300005, maxm = 14400005;
16
17 int Sum[maxm], Son[maxm][2], root[maxm], ndtot;
18
19 void build(int x, int &y, int v, int d) {
20     Sum[y = ++ndtot] = Sum[x] + 1;
21     if (d < 0) return;
22     int p = v >> d & 1;
23     Son[y][p ^ 1] = Son[x][p ^ 1];
24     build(Son[x][p], Son[y][p], v, d - 1);
25 }
26
27 int tot;
28
29 int query(int x, int y, int v, int d) {
30     if (d < 0) return 0;
31     int p = v >> d & 1; int tmp = Sum[Son[y][p ^ 1]] - Sum[Son[x][p ^ 1]];
32     if (tmp > 0) return (1 << d) + query(Son[x][p ^ 1], Son[y][p ^ 1], v, d - 1);
33     else return query(Son[x][p], Son[y][p], v, d - 1);
34 }
35
36 int main() {
37     int n, m;
38     scanf("%d%d", &n, &m);
39     build(root[0], root[1], 0, 24), n++;
40     rep(i, 2, n) {
41         int id;
42         scanf("%d", &id);
43         tot ^= id;
44         build(root[i - 1], root[i], tot, 24);
45     }
46     char op[5];
47     while (m--) {
48         scanf("%s", op);
49         if (op[0] == ‘A‘) {
50             int id;
51             scanf("%d", &id);
52             tot ^= id;
53             build(root[n], root[n + 1], tot, 24);
54             n++;
55         }
56         else {
57             int x, y, k;
58             scanf("%d%d%d", &x, &y, &k);
59             printf("%d\n", query(root[x - 1], root[y], tot ^ k, 24));
60         }
61     }
62 }

      

时间: 2024-08-18 19:31:23

可持久化Trie树初步的相关文章

bzoj4103异或运算 可持久化trie树

要去清华冬令营了,没找到2016年的题,就先坐一坐15年的. 因为n很小,就按照b串建可持久化trie树,a串暴力枚举. 其他的直接看代码. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; inline int read() { int x=0,f=1,ch=getchar(); while(ch<'0'||ch

【bzoj4212】神牛的养成计划 Trie树+可持久化Trie树

题目描述 Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望...... 后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛hzwer很生气,但他知道基因突变的低频性,说不定还有以下优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面你懂的...... 黄学长现在知道了N个细胞的DNA序列,它们是若干个由小写字母组成的字符串.一个优秀的基因是两个字符串s1和s2,当且仅当s1是某序列

【bzoj3281】最大异或和 可持久化Trie树

题目描述 给定一个非负整数序列 {a},初始长度为 N.       有M个操作,有以下两种操作类型:1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2.Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. 输入 第一行包含两个整数 N  ,M,含义如问题描述所示.   第二行包含 N个非负整数,表示初始的序列 A . 接下来 M行,每行描述一个

[bzoj3261]最大异或和[可持久化trie树]

因为要求异或和最大,所以可以考虑从高位开始,向低位枚举尽可能接近~x的值,所以以二进制位为关键字,建立可持久化trie树,根据异或和的性质,XOR_SUM{i,j}=XOR_SUM{1,j} xor XOR_SUM{1,i-1},所以查询问题也可以解决了. 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <c

BZOJ 2741【FOTILE模拟赛】L 分块+可持久化Trie树

题目大意 给出一个序列,求[l, r]中的最大连续xor 和. 强制在线 思路 先把整个序列分成n  √  块,预处理每一块的开头到每个数字的最大连续xor 和.这个我们只需处理出前缀xor 和,之后用可持久化Trie树就可以搞定.这样询问的右边就是整块的了.剩下左边的随便暴力一下就能过了.. CODE #define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring>

【BZOJ3689】异或之 堆+可持久化Trie树

[BZOJ3689]异或之 Description 给定n个非负整数A[1], A[2], ……, A[n].对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数.求这些数(不包含A[i])中前k小的数.注:xor对应于pascal中的“xor”,C++中的“^”. Input 第一行2个正整数 n,k,如题所述.以下n行,每行一个非负整数表示A[i]. Output 共一行k个数,表示前k小的数. Samp

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密

bzoj 3261: 最大异或和 (可持久化trie树)

3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Description 给定一个非负整数序列 {a},初始长度为 N.       有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. Inp

[BZOJ3261&amp;BZOJ3166]可持久化trie树及其应用

可持久化trie树 可持久化trie树现在想来是比较好理解的了,但却看了一个下午... 相当于对于每个状态建立一条链(或者说一棵trie),求解的时候只要让两个点按照相同的步子走然后看sum的大小关系即可. tr[y].son[p xor 1]:=tr[x].son[p xor 1]; tr[y].sum:=tr[x].sum+1; 这两句要好好体会,对之后理解query过程中的语句很有帮助. if (tr[tr[x].son[p xor 1]].sum=tr[tr[x].son[p xor 1