题意:选一个前缀数列异或和 和 一个 后缀数列异或和 (不能重叠,长度可为0)求他们异或的最大值
思路:第一次接触字典树的这种用法T T,可以快速查找一个集合里面和他异或和最大的数,那只要从左到右 往前推一次 就好
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<queue>
#include<math.h>
using namespace std;
#define LL long long
#define M 100100
#define N 6000100
int nxt[N][2];
int val[N];
int a[60];
int cnt;
LL in[M];
void add(LL x)
{
for(int i=59;i>=0;i--)
{
if((x&(1LL<<i))>0)
a[i]=1;
else
a[i]=0;
}
int head=0;
for(int i=59;i>=0;i--)
{
if(nxt[head][a[i]]==-1)
{
nxt[head][a[i]]=++cnt;
memset(nxt[cnt],-1,sizeof(nxt[cnt]));
}
head=nxt[head][a[i]];
val[head]++;
}
}
LL query(LL x)
{
for(int i=59;i>=0;i--)
{
if((x&(1LL<<i))>0)
a[i]=1;
else
a[i]=0;
}
int head=0;
LL ans=0;
for(int i=59;i>=0;i--)
{
int temp=nxt[head][a[i]^1];
if(temp==-1||val[temp]==0)
temp=nxt[head][a[i]];
else
ans=ans+(1LL<<i);
head=temp;
}
return ans;
}
void remo(LL x)
{
for(int i=59;i>=0;i--)
{
if((x&(1LL<<i))>0)
a[i]=1;
else
a[i]=0;
}
int head=0;
for(int i=59;i>=0;i--)
{
head=nxt[head][a[i]];
val[head]--;
}
}
int main()
{
int n;
scanf("%d",&n);
LL ans=0;
LL sum=0;
memset(nxt[0],-1,sizeof(nxt[0]));
for(int i=1;i<=n;i++)
{
scanf("%lld",&in[i]);
sum^=in[i];
add(sum);
ans=max(ans,sum);
}
LL t=0;
for(int i=n;i>1;i--)
{
t^=in[i];
remo(sum);
sum^=in[i];
ans=max(ans,query(t));
ans=max(ans,t);
}
printf("%lld\n",ans);
return 0;
}