t组数据
每组n个值
求出最大异或和区间的总异或值
利用了异或的性质, 应该也可以用线段树维护区间的想法做(类似线段树维护最大区间和, 利用前缀和后缀的想法)
假设输入了第四个数x4
则二叉字典树中已经存储了 x1、x1^x2、x1^x2^x3 的值, 此时计算出 x1^x2^x3^x4 的值并进行询问, 尽量取每一个二进制位相反使得结果该二进制位为1, 由于相同数异或为0后可消去的性质, 可以直接得出1~4区间内的最大区间异或和, 然后与前最大值ans比较, 最终得出整个序列的最大异或区间的总异或值
#define _CRT_SECURE_NO_WARNINGS 1
#include<bits/stdc++.h>
#include <unordered_set>
typedef long long ll;
using namespace std;
int t;
int arr[100010];
int n;
int son[100010 * 31][2]; //二叉字典树
int cnt[100010 * 31]; //节点i出现次数
int idx = 0;
void insert(int x, int v) //x表示要插入或删除的数字, v为1或-1, 表示插入或删除
{
int p = 0;
for (int i = 30; i >= 0; i--)
{
int u = (x >> i) & 1; //取出x的二进制前31位
if (!son[p][u]) //若p节点没有u位上的孩子, 若已有则无需执行
{
//idx++; //制造一个新下标用于指向p节点的新孩子
son[p][u] = ++idx;
}
p = son[p][u]; //前往下一个节点
cnt[p] += v; //下一个节点计数增加或减少
}
}
int query(int x)
{
int p = 0, r = 0;
for (int i = 30; i >= 0; i--)
{
int u = (x >> i) & 1;
if (cnt[son[p][!u]]) //如果有反向点, 就顺着反向点走
{
p = son[p][!u];
r = r * 2 + 1;
}
else //没有反向点就顺着原方向走
{
p = son[p][u];
r = r * 2;
}
}
return r;
}
int main()
{
scanf("%d", &t);
while (t--)
{
for (int i = 0; i <= idx+1; i++) {
son[i][0] = son[i][1] = 0;
cnt[i] = 0;
}
idx = 0;
scanf("%d", &n);
int ans = 0, s = 0;
arr[0] = 0;
insert(arr[0], 1);
for (int i = 1; i <= n; i++)
{
int x;
scanf("%d", &x);
arr[i] = arr[i - 1] ^ x;
ans = max(ans, query(arr[i]));
insert(arr[i], 1);
}
printf("%d\n", ans);
}
}