可持久化Trie樹初步

可持久化Trie樹和可持久化線段樹很像,依次插入信息,經過減法來進行歷史版本查詢。c++

2015年11月27日數據結構

  bzoj3261 最大異或和ide

    咱們須要計算 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樹。ui

    同時題目中有區間限制,因此咱們須要一個可持久化的數據結構。spa

    1) 順次將sum[i]插入到可持久化Trie樹中。注意 : 咱們須要讓數位對齊,不然高位低位會錯位,因此須要在每個數的前面加上適當的0以使他們數位相等。3d

    插入時,能夠採起遞歸的方式,用 >> 來肯定這一位是多少,把沒有改變的那一邊鏈向歷史版本。注意 : 在遞歸時,若採起d--(此處見代碼)的方式,由於一個節點的左右兒子不是在同一個遞歸中構造完成,因此判斷 d < 0  ---> break; 須要放在新建節點以後。code

    2) 對於查詢時,從根節點開始,一樣採用d--的方式,逐位肯定,若是 x 的這一位爲 p ,那麼咱們查詢Sum[son[l][p ^ 1]] - Sum[son[r][p ^ 1],Sum爲節點上有多少的值,如若 表達式 > 0 那麼咱們就像 p ^ 1 的方向行走,同時 答案加上 1 << d 由於這一位被咱們錯開了,不然只好向 p 的方向行走, 不加上 1 << d。
blog

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

 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 }
View Code
相關文章
相關標籤/搜索