原题链接
题意:给你n个数求一段区间[l,r]使得该区间的异或和最大,若有多个,求区间右端点最小的那个,如果还有多个,求区间长度最段的那个
思路:先求一个异或前缀和,假设最后答案是[x,y]区间,那么就是[1,x]区间的异或和 与 [1,y]区间的异或和 异或的结果,用为每一个前缀和构造0-1字典树(从高位到低位),然后枚举前缀和pre[i] 在字典树上查询。
同样的,也可以求树上的一条路径(u,v)间的异或极值
代码:
//#pragma GCC optimize("Ofast")
//#pragma GCC target("avx,avx2,fma")
//#pragma GCC optimization ("unroll-loops")
#include <bits/stdc++.h>
#define pb push_back
#define ll long long
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
int n,a[100005];
int pre[100005],val;
int p[100];
map<int,int> Map;
int tree[3500000][3],k=1;
void insertt()
{
int os=0;
for(int i=0;i<22;i++)
{
int c=p[i];
if(tree[os][c]==0)
{
tree[os][c]=k;
k++;
}
os=tree[os][c];
}
}
void query(ll x)
{
int os=0;
for(int i=21;i>=0;i--)
{
int c=(x>>i)&1;
if(c==0)
{
if(tree[os][1]!=0)
{val+=(1<<i);
os=tree[os][1];}
else
{os=tree[os][0];}
}
else
{
if(tree[os][0]!=0)
{os=tree[os][0];}
else
{val+=(1<<i);
os=tree[os][1];}
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{cin>>a[i];}
if(n==1)
{
cout<<a[1]<<" 1 1"<<endl;
return 0;
}
for(int i=1;i<=n;i++)
{
pre[i]=pre[i-1]^a[i];
if(Map[pre[i]]==0)
{Map[pre[i]]=i;}
int op=pre[i],cnt=0;
for(int j=21;j>=0;j--)
{
p[cnt++]=(op>>j)&1;
}
insertt();
}
int maxx=0,px=0,py=0,maxp,minp;
for(int i=1;i<=n;i++)
{
val=0;
query(pre[i]);
if(val==0){maxp=i;minp=i;}
else{maxp=max(Map[val],i);minp=min(Map[val],i);}
if((val^pre[i])>maxx)
{
maxx=val^pre[i];
px=minp;
py=maxp;
}
if((val^pre[i])==maxx)
{
if(maxp<py)
{
px=minp;
py=maxp;
}
if(maxp==py)
{
if(minp>px)
{
px=minp;
py=maxp;
}
}
}
}
if(px==py)
{cout<<maxx<<" "<<px<<" "<<py<<endl;}
else
{cout<<maxx<<" "<<px+1<<" "<<py<<endl;}
return 0;
}