bzoj3261: 最大異或和 (可持久化trie樹)
阿新 • • 發佈:2018-12-18
多少 ace 經典 經典的 bzoj3261 個數 math 應該 sum
題目鏈接
題解
看到異或和最大就應該想到01 trie樹
我們記\(S_i\)為前i項的異或和
那麽我們的目的是最大化\(S_n\)^\(x\)^\(S_{j-1}\) \((l <= j <= r)\) (註意是\(j-1\), 所以l和r都要減1)
\(S_n\)^\(x\)已經固定, 那麽我們可以把\(S_j\)放入trie樹搞
那麽怎麽處理區間呢?
類似主席樹
記錄一下\([1-i]\)每個節點被多少個數經過
那麽兩棵trie樹相減,就得到了 \([l-r]\)這段區間的信息
然後就是經典的模型了
Code
#include<bits/stdc++.h> const int N = 600010, M = 25; #define LL long long #define RG register int ch[N*30][2], sum[N*30], root[N], cnt, tot, ans; using namespace std; inline int gi() { RG int x = 0; RG char c = getchar(); bool f = 0; while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1; while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar(); return f ? -x : x; } void insert(int &now, int x, int dep) { sum[++cnt] = sum[now]+1; ch[cnt][0] = ch[now][0]; ch[cnt][1] = ch[now][1]; now = cnt; if (dep < 0) return ; insert(ch[now][(x >> dep) & 1], x, dep-1); return ; } void query(int rt1, int rt2, int x, int dep) { if (dep < 0) return ; int k = (x >> dep)&1; if (sum[ch[rt2][k^1]]-sum[ch[rt1][k^1]] > 0) { ans |= (1 << dep); query(ch[rt1][k^1], ch[rt2][k^1], x, dep-1); } else query(ch[rt1][k], ch[rt2][k], x, dep-1); return ; } int main() { //freopen(".in", "r", stdin); //freopen(".out", "w", stdout); int n = gi(), m = gi(); for (int i = 1; i <= n; i++) { int x = gi(); tot ^= x; root[i] = root[i-1]; insert(root[i], tot, M-1); } for (int i = 1; i <= m; i++) { char c = getchar(); while (c != 'A' && c != 'Q') c = getchar(); if (c == 'A') { int x = gi(); tot ^= x; root[n+1] = root[n]; insert(root[++n], tot, M-1); } else { int l = gi()-1, r = gi()-1, x = gi(); ans = 0; query(root[l-1], root[r], tot^x, M-1); if (!l) ans = max(ans, tot^x); printf("%d\n", ans); } } return 0; }
bzoj3261: 最大異或和 (可持久化trie樹)