求某个数与一些数异或的最大值是字典树应用的一个经典问题。
主要思想是贪心,把数字都转化成二进制,把这些数按存到字典树中。从高位开始遍历,如果有不同的边(可以使得异或值为1)肯定走不同的边,如果没有则走与自己值相同的边(一定存在)。边走边统计,最后输出。
这道题题意是:输入一个数组,再给一些数字进行查询,问这些数字与数组中的哪个元素异或值最大。
思路:把输入的数组元素全部插入字典树,然后按照上面说的方法进行查询。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N = 3000000+5;
typedef long long LL;
struct Trie {
int next[2];
LL v;
void init() {
v = -1;
memset(next, -1, sizeof(next));
};
};
Trie trie[N];
int sz;
void init() {
sz = 1;
trie[0].init();
}
void myinsert(LL x) {
int p = 0;
for(int i = 32; i>= 0; i--) {
int ch;
if(x&(1ll<<i)) ch = 1;
else ch = 0;
if(trie[p].next[ch] == -1) {
trie[p].next[ch] = sz;
trie[sz++].init();
}
p = trie[p].next[ch];
}
trie[p].v = x;
}
LL query(LL q) {
int p = 0;
LL ret = 0;
for(int i = 32; i >= 0; i--) {
int ch = q&(1ll<<i)?1:0;
if(trie[p].next[!ch] != -1) {
ret |= (1ll<<i);
p = trie[p].next[!ch];
}
else p = trie[p].next[ch];
}
return trie[p].v;
}
int main() {
int t;
scanf("%d", &t);
for(int cas = 1; cas <= t; cas++) {
init();
int n, m;
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) {
LL x;
scanf("%lld", &x);
myinsert(x);
}
printf("Case #%d:\n", cas);
while(m-- > 0) {
LL q;
scanf("%lld", &q);
printf("%lld\n", query(q));
}
}
return 0;
}