BZOJ 3261 最大異或和(算競進階習題)
阿新 • • 發佈:2019-03-19
ons min code 序列 二進制 printf 32位 lcm test
可持久化Trie
需要知道一個異或的特點,和前綴和差不多
a[p] xor a[p+1] xor....xor a[n] xor x = a[p-1] xor a[n] xor x
所以我們把a[1...n]的異或和預處理出來,用s[i]表示,用一個可持久化Trie維護
問題就轉化成s[n] xor x = val,求一個序列與val異或的最大值
第i個Trie的root對應維護s[1..i],這樣我們在查詢值的時候為了保證在[...r-1]之類,只要查詢r-1及之前的版本
為了保證在[l-1...]內,我們還需要一個數組latest維護末尾節點是最近一次第幾個s的末尾,查詢的時候跳過小於l-1的版本即可
這題洛谷上卡常。。根據題目給的範圍,24位二進制足夠了,沒必要開32位,節約時間。。還有各種inline,快讀,盡量用上
為了保證能夠查詢[1..r],我們還需要給空樹插入一個0,保證覆蓋整個區間(類似主席樹)
#include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; inline int lowbit(int x){ return x & (-x); } inline int read(){ int X = 0, w = 0; char ch = 0; while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); } while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar(); return w ? -X : X; } inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; } inline int lcm(int a, int b){ return a / gcd(a, b) * b; } template<typename T> inline T max(T x, T y, T z){ return max(max(x, y), z); } template<typename T> inline T min(T x, T y, T z){ return min(min(x, y), z); } template<typename A, typename B, typename C> inline A fpow(A x, B p, C lyd){ A ans = 1; for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd; return ans; } const int N = 600005; int n, m, trie[N*24][2], latest[N*24], s[N], root[N], tot; inline void insert(int k, int i, int p, int q){ if(i < 0){ latest[p] = k; return; } int t = (s[k] >> i) & 1; if(q) trie[p][t^1] = trie[q][t^1]; trie[p][t] = ++tot; insert(k, i - 1, trie[p][t], trie[q][t]); latest[p] = max(latest[trie[p][0]], latest[trie[p][1]]); } inline int query(int cur, int i, int val, int lmt){ if(i < 0) return s[latest[cur]] ^ val; int t = (val >> i) & 1; if(latest[trie[cur][t^1]] >= lmt) return query(trie[cur][t^1], i - 1, val, lmt); return query(trie[cur][t], i - 1, val, lmt); } int main(){ memset(latest, -1, sizeof latest); n = read(), m = read(); root[0] = ++tot; insert(0, 23, root[0], 0); for(int i = 1; i <= n; i ++){ s[i] = s[i - 1] ^ read(); root[i] = ++tot; insert(i, 23, root[i], root[i - 1]); } while(m --){ char opt[2]; scanf("%s", opt); if(opt[0] == 'A'){ int x = read(); root[++n] = ++tot, s[n] = s[n - 1] ^ x; insert(n, 23, root[n], root[n - 1]); } else if(opt[0] == 'Q'){ int l = read(), r = read(), x = read(); printf("%d\n", query(root[r - 1], 23, s[n] ^ x, l - 1)); } } return 0; }
BZOJ 3261 最大異或和(算競進階習題)