奶牛異或(字典樹求異或極值)
阿新 • • 發佈:2021-02-01
技術標籤:題解
原題連結
題意:給你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;
}