用Trie(字典树),建树时,根据每个数字的对应的二进制串构造一个二叉树,每个结点两个分支,分支指向的两个son结点分别表示当前位的数值为0或1,记录每次输入的数字转化成的二进制串,当前位为1,就走到数值为1的结点,否则走到0结点,这样每个数字对应的Trie中的路径就是唯一的。
因为要求异或值最大,在第一个数字固定的情况下,尽可能地让第二个数的每一位都与第一个数的对应位相反,这样最终确定的第二个数与第一个数的异或值就最大,所以总的时间复杂度$o(n*logn)$;
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10, M = 3e6 + 10;//M=31*N
int a[N], son[M][2], idx;
void insert(int x) {
int p = 0;
for (int i = 30; i >= 0; i--) {
int s = x >> i & 1;
if (!son[p][s]) son[p][s] = ++idx;
p = son[p][s];
}
}
int query(int x) {
int p = 0;
int res = 0;
for (int i = 30; i >= 0; i--) {
int s = x >> i & 1;
if (son[p][!s]) {
res += 1 << i;
p = son[p][!s];
} else p = son[p][s];
}
return res;
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
insert(a[i]);
}
int res = 0;
for (int i = 0; i < n; i++)
res = max(res, query(a[i]));
cout << res;
return 0;
}