可持久化Trie树初步
2015-11-27 13:59
190 查看
可持久化Trie树和可持久化线段树很像,依次插入信息,通过减法来进行历史版本查询。
2015年11月27日
bzoj3261 最大异或和
我们需要计算 a[p] xor a[p+1] xor ... xor a
xor x ,设 sum[i] 表示 a[1] xor a[2] xor ... xor a[i] 的值,因为异或满足区间减法,所以求上一个式子等于求 sum
xor sum[p - 1] xor x,进一步,sum
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
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)
View Code
2015年11月27日
bzoj3261 最大异或和
我们需要计算 a[p] xor a[p+1] xor ... xor a
xor x ,设 sum[i] 表示 a[1] xor a[2] xor ... xor a[i] 的值,因为异或满足区间减法,所以求上一个式子等于求 sum
xor sum[p - 1] xor x,进一步,sum
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
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)
#include <bits/stdc++.h> #define rep(i, a, b) for (int i = a; i <= b; i++) #define REP(i, a, b) for (int i = a; i < b; i++) #define drep(i, a, b) for (int i = a; i >= b; i--) #define pb push_back #define mp make_pair #define xx first #define yy second using namespace std; typedef long long i64; typedef pair<int, int> pii; const int inf = ~0U >> 1; const i64 INF = ~0ULL >> 1; //***************************** const int maxn = 300005, maxm = 14400005; int Sum[maxm], Son[maxm][2], root[maxm], ndtot; void build(int x, int &y, int v, int d) { Sum[y = ++ndtot] = Sum[x] + 1; if (d < 0) return; int p = v >> d & 1; Son[y][p ^ 1] = Son[x][p ^ 1]; build(Son[x][p], Son[y][p], v, d - 1); } int tot; int query(int x, int y, int v, int d) { if (d < 0) return 0; int p = v >> d & 1; int tmp = Sum[Son[y][p ^ 1]] - Sum[Son[x][p ^ 1]]; if (tmp > 0) return (1 << d) + query(Son[x][p ^ 1], Son[y][p ^ 1], v, d - 1); else return query(Son[x][p], Son[y][p], v, d - 1); } int main() { int n, m; scanf("%d%d", &n, &m); build(root[0], root[1], 0, 24), n++; rep(i, 2, n) { int id; scanf("%d", &id); tot ^= id; build(root[i - 1], root[i], tot, 24); } char op[5]; while (m--) { scanf("%s", op); if (op[0] == 'A') { int id; scanf("%d", &id); tot ^= id; build(root , root[n + 1], tot, 24); n++; } else { int x, y, k; scanf("%d%d%d", &x, &y, &k); printf("%d\n", query(root[x - 1], root[y], tot ^ k, 24)); } } }
View Code
相关文章推荐
- iOS学习笔记:神奇的IB_DESIGNABLE和IBInspectable
- 随手写个网络通讯情况监控“微系统”
- 1069. The Black Hole of Numbers (20)
- Python安装配置
- 如何将一个已经编译好的service的bin档/jar文件编译进system/bin目录下
- Deployment failed because of an internal error: Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE]
- Spring Quartz实现定时任务的配置方法
- alsamixer修改linux声音参数
- 使用映射接口实现数据库的操作
- cron表达式
- 软件行业中的鱼骨图运用
- spring取容器
- Mac OS 中NSSavePanel以及NSOpenPanel的使用
- 负载均衡的几种常用方案
- httpclient与webapi
- shell基础
- 1065. A+B and C (64bit) (20)
- ThinkPHP框架短信接口
- 黑马程序员—Java基础—多线程
- 1061. Dating (20)