貌似可以解决一些跟异或相关的问题?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #include<vector> 2 #include<cstdio> 3 #include<iostream> 4 #define pb push_back 5 #define nc getchar 6 #define read(x) scanf("%d", &x) 7 using namespace std; 8 struct Edge{int v, w, n;} E[200005]; 9 int n, d[100005], head[100005], ec; 10 inline void aE(int u, int v, int w) { 11 E[++ec] = (Edge){v, w, head[u]}; head[u] = ec; 12 E[++ec] = (Edge){u, w, head[v]}; head[v] = ec; 13 } 14 void dfs(int u, int f, int w) { 15 d[u] = w; for (int i = head[u]; i; i = E[i].n) 16 if (E[i].v != f) dfs(E[i].v, u, E[i].w ^ w); 17 } 18 struct Node { 19 Node *ch[2]; 20 } Tnull, *null = &Tnull, *root; 21 Node mem[2000000], *C; 22 inline Node* newNode() { 23 C->ch[0] = C->ch[1] = null; return C++; 24 } 25 void insert(int x) { 26 Node *u = root; 27 for (int i = 31; ~i; --i) { 28 int c = (x >> i) & 1; 29 if (u->ch[c] == null) u->ch[c] = newNode(); 30 u = u->ch[c]; 31 } 32 } 33 int find(int x) { 34 Node *u = root; int res = 0; 35 for (int i = 31; ~i; --i) { 36 int c = !((x >> i) & 1); 37 if (u->ch[c] == null) u = u->ch[!c]; 38 else u = u->ch[c], res += 1 << i; 39 } return res; 40 } 41 void solve() { 42 for (int i = 1; i <= n; ++i) insert(d[i]); int res = 0; 43 for (int i = 1; i <= n; ++i) res = max(res, find(d[i])); 44 printf("%d\n", res); 45 } 46 int main() { 47 while (~scanf("%d", &n)) { 48 for (int u, v, w, i = 1; i < n; ++i) 49 read(u), read(v), read(w), aE(u + 1, v + 1, w); 50 for (int i = head[1]; i; i = E[i].n) dfs(E[i].v, 1, E[i].w); 51 C = mem; root = newNode(); solve(); 52 for (int i = 1; i <= n; ++i) d[i] = 0; 53 for (int i = 1; i <= n; ++i) head[i] = 0; 54 ec = 0; 55 } 56 return 0; 57 }
这题咱用vector存边T了。
记f(i)为从根节点出发到i点时边权的异或和。
根据异或的性质,u-v这条路径的异或和就是f(u) xor f(v)。
把所有的f(i)都插入一个01trie上,然后枚举一个f(i),再贪心另一个。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include<cstdio> #include<iostream> using namespace std; inline char nc() { static char b[1<<12],*s=b,*t=b; return s==t&&(t=(s=b)+fread(b,1,1<<12,stdin),s==t)?-1:*s++; } inline void read(int &x) { char b = nc(); x = 0; for (; !isdigit(b); b = nc()); for (; isdigit(b); b = nc()) x = x * 10 + b - '0'; } inline int read() { char b = nc(); for (; !isalpha(b); b = nc()); return b == 'A'; } struct Node { Node *ch[2]; int v; } Tnull, *null = &Tnull; Node mem[24000010], *rt[600010], *C = mem; inline Node* newNode() { C->ch[0] = C->ch[1] = null; C->v = 0; return C++; } int n, m, xr; void insert(int x, Node *u, Node *p) { for (int i = 24; ~i; --i) { int c = (x >> i) & 1; if (u->ch[c] == null) u->ch[c] = newNode(); u->ch[!c] = p->ch[!c]; u = u->ch[c]; p = p->ch[c]; u->v = p->v + 1; } } int query(int x, Node *L, Node *R) { int res = 0; for (int i = 24; ~i; --i) { int c = !((x >> i) & 1); if (R->ch[c]->v - L->ch[c]->v > 0) res += 1 << i; else c = !c; // R->ch[c]->v - L->ch[c]->v > 0 ? res += 1 << i : c = !c; R = R->ch[c], L = L->ch[c]; } return res; } int main() { null->ch[0] = null->ch[1] = null; read(n); read(m); ++n; rt[0] = newNode(); rt[1] = newNode(); insert(0, rt[1], rt[0]); for (int i = 2, t; i <= n; ++i) read(t), xr ^= t, rt[i] = newNode(), insert(xr, rt[i], rt[i-1]); for (int x, l, r, i = 0; i < m; ++i) { if (read()) { read(x); xr ^= x; ++n; rt[n] = newNode(); insert(xr, rt[n], rt[n-1]); } else { read(l); read(r); read(x); printf("%d\n", query(xr ^ x, rt[l-1], rt[r])); } } return 0; }
记 $f_n = a_1 \; xor \; a_2 \; xor \; ... \; xor \; a_n$
即求 $x \; xor \; f_n \; xor \; f_{p-1}$ 的最大值。
注意到 $x \; xor \; f_n$ 为一定值,所以我们只需要在只存$[l-1, r-1]$这段区间值的trie上贪心就行。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #include<queue> 2 #include<cstdio> 3 #include<iostream> 4 #define nc getchar 5 using namespace std; 6 inline void read(int &x) { 7 char b = nc(); x = 0; 8 for (; !isdigit(b); b = nc()); 9 for (; isdigit(b); b = nc()) x = x * 10 + b - '0'; 10 } 11 struct Node { 12 Node *ch[2]; int sz; 13 } Tnull, *null = &Tnull, *root; 14 Node mem[3200000], *C = mem; 15 inline Node* newNode() { 16 C->sz = 0; C->ch[0] = C->ch[1] = null; return C++; 17 } 18 void insert(int x) { 19 Node *u = root; ++u->sz; 20 for (int i = 30; ~i; --i) { 21 int c = (x >> i) & 1; 22 if (u->ch[c] == null) u->ch[c] = newNode(); 23 u = u->ch[c]; ++u->sz; 24 } 25 } 26 int query(int x, int k) { 27 Node *u = root; int res = 0; 28 for (int i = 30; ~i; --i) { 29 int c = (x >> i) & 1; 30 if (k > u->ch[c]->sz) 31 res |= 1 << i, k -= u->ch[c]->sz, c = !c; 32 u = u->ch[c]; 33 } return res; 34 } 35 struct Info { 36 int v, k, p; 37 inline bool operator<(const Info &o) const {return v > o.v;} 38 }; 39 int n, m, a[100010]; 40 priority_queue < Info > q; 41 int main() { 42 read(n); read(m); m *= 2; root = newNode(); 43 for (int i = 1; i <= n; ++i) read(a[i]), insert(a[i]); 44 for (int i = 1; i <= n; ++i) q.push((Info){query(a[i], 2), 2, i}); 45 while (m--) { 46 Info h = q.top(); q.pop(); 47 if (m & 1) printf("%d ", h.v); 48 if (h.k == n) continue; 49 q.push((Info){query(a[h.p], h.k + 1), h.k + 1, h.p}); 50 } 51 return 0; 52 }
堆+01trie。
在trie树上的每个节点处记录一个v,表示经过的次数,这样就可以资磁查询第k大的操作了。
用一个堆来维护当前最小的异或值。要记录这个值是从哪里来的,第几大。
因为$x_i \; xor \; x_j$ 和 $x_j \;xor\; x_i$ 是一种情况,所以要循环2k次,并在奇数次输出。
然后再找到a_i异或后的第k+1大值,放入堆中。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #include<queue> 2 #include<cstdio> 3 #include<iostream> 4 using namespace std; 5 inline char nc() { 6 static char b[1<<14],*s=b,*t=b; 7 return s==t&&(t=(s=b)+fread(b,1,1<<14,stdin),s==t)?-1:*s++; 8 } 9 inline void read(int &x) { 10 char b = nc(); x = 0; 11 for (; !isdigit(b); b = nc()); 12 for (; isdigit(b); b = nc()) x = x * 10 + b - '0'; 13 } 14 struct Node { 15 Node *ch[2]; int sz; 16 } Tnull, *null = &Tnull, *rt[300010], *L[1005], *R[1005]; 17 Node mem[20000000], *C = mem; 18 inline Node* newNode() { 19 C->ch[0] = C->ch[1] = null; C->sz = 0; return C++; 20 } 21 int n, m, a[1005], q; 22 void insert(int x, Node *u, Node *v) { 23 for (int c, i = 30; ~i; --i) { 24 c = (x >> i) & 1; 25 if (u->ch[c] == null) u->ch[c] = newNode(); 26 u->ch[!c] = v->ch[!c]; 27 u = u->ch[c]; v = v->ch[c]; u->sz = v->sz + 1; 28 } 29 } 30 int query(Node *ll, Node *rr, int l, int r, int k) { 31 int res = 0; 32 for (int i = l; i <= r; ++i) L[i] = ll, R[i] = rr; 33 for (int c, sz, d = 30; ~d; --d) { 34 sz = 0; 35 for (int i = l; i <= r; ++i) { 36 c = (a[i] >> d) & 1; 37 sz += R[i]->ch[c]->sz - L[i]->ch[c]->sz; 38 } 39 if (k <= sz) { 40 for (int i = l; i <= r; ++i) { 41 c = (a[i] >> d) & 1; 42 L[i] = L[i]->ch[c]; R[i] = R[i]->ch[c]; 43 } 44 } else { 45 k -= sz; res |= 1 << d; 46 for (int i = l; i <= r; ++i) { 47 c = !((a[i] >> d) & 1); 48 L[i] = L[i]->ch[c]; R[i] = R[i]->ch[c]; 49 } 50 } 51 } return res; 52 } 53 int main() { 54 read(n); read(m); null->ch[0] = null->ch[1] = null; 55 for (int i = 0; i <= m; ++i) rt[i] = newNode(); 56 for (int i = 1; i <= n; ++i) read(a[i]); 57 for (int t, i = 1; i <= m; ++i) read(t), insert(t, rt[i], rt[i-1]); 58 read(q); 59 for (int i = 0, u, d, l, r, k; i < q; ++i) { 60 read(u); read(d); read(l); read(r); read(k); 61 printf("%d\n", query(rt[l-1], rt[r], u, d, (r - l + 1) * (d - u + 1) - k + 1)); 62 } 63 return 0; 64 }
注意到n很小而m很大,所以我们在m上建立可持久化trie树,n直接暴力就行。
查询第k大也很好搞,咱只要看看使异或值小的个数就行,看看与当前二进制位相同的儿子的size就行。