题目连接:BZOJ - 4103php
THUSC滚粗以后一直没有写这道题,历来没写过可持久化Trie,发现其实和可持久化线段树都是同样的。嗯,有些东西就是明白得太晚。ios
首先Orz ZYF-ZYF 神犇的题解。数组
题目给出的 n 和 m 的范围差异很大,n 很小,m 很大,所以能够想到 n 的范围是为了直接暴力枚举。ui
题目要求的就是 A 的一段区间中的数和 B 的一段区间中的数的异或的第 k 大值。spa
位运算有关的题目,通常是从高位到低位贪心之类的。blog
区间异或,通常要使用可持久化 Trie。get
咱们对于范围大的 B 数组创建可持久化 Trie,这样就能够提取 B 数组的一个区间了。博客
从高位到低位,枚举 A 数组区间中的每一个元素,根据 Trie 结点的信息,求出这一位为 0 和 为 1 的各有多少,并据此肯定答案的这一位。string
要注意的是,A 数组区间中每一个元素要对应的 Trie 结点是不一样的,由它们的前几位肯定(由于它们的前几位不一样,可是要求异或以后前几位相同)。it
编辑完这篇博客以后仍是一个一个地添加了标签,虽然这个blog立刻就要停更了,感受这几天写的任何一篇都有多是最后一篇。
奇怪的感受。
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; const int MaxN = 1000 + 5, MaxM = 300000 + 5, MaxNode = 10000000 + 5; int n, m, p, Index, Ans; int A[MaxN], B[MaxM], Root[MaxM], Son[MaxNode][2], T[MaxNode], F[MaxN], Q[MaxN]; bool OK[MaxN]; void Build(int &x, int y, int Num, int Bit) { if (!x) x = ++Index; if (Bit == 0) { T[x] = T[y] + 1; return; } if (Num & (1 << (Bit - 1))) { Son[x][0] = Son[y][0]; Build(Son[x][1], Son[y][1], Num, Bit - 1); } else { Son[x][1] = Son[y][1]; Build(Son[x][0], Son[y][0], Num, Bit - 1); } T[x] = T[Son[x][0]] + T[Son[x][1]]; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", &A[i]); for (int i = 1; i <= m; ++i) { scanf("%d", &B[i]); Build(Root[i], Root[i - 1], B[i], 31); } scanf("%d", &p); int u, d, l, r, kk; for (int i = 1; i <= p; ++i) { scanf("%d%d%d%d%d", &u, &d, &l, &r, &kk); kk = (d - u + 1) * (r - l + 1) - kk + 1; Ans = 0; for (int j = u; j <= d; ++j) { F[j] = Root[r]; Q[j] = Root[l - 1]; } for (int j = 30; j >= 0; --j) { int x, Temp = 0; for (int k = u; k <= d; ++k) { x = (A[k] & (1 << j)); if (x) Temp += T[Son[F[k]][1]] - T[Son[Q[k]][1]]; else Temp += T[Son[F[k]][0]] - T[Son[Q[k]][0]]; } if (Temp >= kk) { for (int k = u; k <= d; ++k) { x = (A[k] & (1 << j)); if (x) { F[k] = Son[F[k]][1]; Q[k] = Son[Q[k]][1]; } else { F[k] = Son[F[k]][0]; Q[k] = Son[Q[k]][0]; } } } else { kk -= Temp; Ans |= (1 << j); for (int k = u; k <= d; ++k) { x = (A[k] & (1 << j)); if (x) { F[k] = Son[F[k]][0]; Q[k] = Son[Q[k]][0]; } else { F[k] = Son[F[k]][1]; Q[k] = Son[Q[k]][1]; } } } } printf("%d\n", Ans); } return 0; }