地址:https://www.lydsy.com/JudgeOnline/problem.php?id=4260
思路:求不相交的两个连续区间异或值的和的最大值,那么可以分别求出连续区间异或值的前缀最大值 L[i] 和后缀最大值 R[i],
这样 Max=max{L[i]+R[i+1]}
关于前缀最大值L[i],由于必须是连续区间,则可以利用前缀异或和 ml[i]来建立 01字典树。
因为 ml[l]^ml[r] = a[l+1,r]的异或和,那么以a[i]为区间右端点的区间异或最大值就为对 ml[i]查找树的最大值Find(ml[i])
这样就 求L[i]=max(L[i-1],Find(ml[i]),对于 R[i]同理处理即可
Code :
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_N=400005;
const int MAX_S=12800005;
int n;
int a[MAX_N];
int ml[MAX_N],mr[MAX_N]; //异或前缀和,异或后缀和
int Trie[MAX_S][2],num;
bool Sum[MAX_S];
int L[MAX_N],R[MAX_N];
void Insert(int x); //将前缀和当做元素插入
int Find(int x);
int main()
{
scanf("%d",&n);
Insert(0);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
ml[i]=ml[i-1]^a[i];
Insert(ml[i]);
L[i]=max(Find(ml[i]),L[i-1]);
}
memset(Trie,0,sizeof(Trie));
memset(Sum,0,sizeof(Sum));
num=0;
Insert(0);
for(int i=n;i>=1;--i)
{
mr[i]=mr[i+1]^a[i];
Insert(mr[i]);
R[i]=max(Find(mr[i]),R[i+1]);
}
int ans=0;
for(int i=1;i<n;++i)
ans=max(ans,L[i]+R[i+1]);
printf("%d\n",ans);
return 0;
}
void Insert(int x)
{
int u=0,t;
for(int i=31;i>=0;--i)
{
t=(x>>i)&1;
if(!Trie[u][t]) Trie[u][t]=++num;
u=Trie[u][t];
Sum[u]=1;
}
}
int Find(int x)
{
int u=0,t,p,res=0;
for(int i=31;i>=0;--i)
{
t=(x>>i)&1;
p=Trie[u][!t];
if(p&&Sum[p]){
res=res|(1<<i);
u=p;
}else u=Trie[u][t];
}
return res;
}