题意:给定长度为n的整数序列,一个连续子段的收益为子段次大值xor子段中任意数,求最大收益子段值
Sol:
考虑枚举次大值是谁,则一个数作为次大值时的扩张范围是[左边第二个大于她的数+1 , 右边第一个大于她的数-1] 和 [左边第一个大于她的数+1 , 右边第二个大于她的数-1]
两个区间可以合并起来,用可持久化Trie查询最大异或值。
找左右数可以将所有数从小到大排序后顺序枚举,每次插入到set里查询
也可以用双向链表维护,每次删除即可
Code:
#include<bits/stdc++.h>
#define debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
const int maxn = 50009;
const int Log = 30;
const int inf = 0x3f3f3f3f;
int n,mx,ans;
int pre[maxn],nxt[maxn],rt[maxn];
struct Trie
{
int son[maxn*Log*2][2],cnt[maxn*Log*2];
int tot;
inline int insert(int x,int num)
{
int tmp,y;tmp=y=++tot;
for(int i=Log;i>=0;i--)
{
son[y][0]=son[x][0];son[y][1]=son[x][1];
cnt[y]=cnt[x]+1;
int wh=(num>>i)&1;
son[y][wh]=++tot;
x=son[x][wh];y=son[y][wh];
}cnt[y]=cnt[x]+1;
return tmp;
}
inline int query(int l,int r,int num)
{
int res=0;
for(int i=Log;i>=0;i--)
{
int wh=(num>>i)&1;
if(cnt[son[r][wh^1]]-cnt[son[l][wh^1]]) res|=(1<<i),r=son[r][wh^1],l=son[l][wh^1];
else r=son[r][wh],l=son[l][wh];
}
return res;
}
}uuz;
struct node{int pos,val;}a[maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline bool cmp(const node &x,const node &y)
{
return x.val<y.val;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
a[i]=(node){i,read()};
rt[i]=uuz.insert(rt[i-1],a[i].val);
}
for(int i=1;i<=n;i++) pre[i]=i-1,nxt[i]=i+1;
pre[0]=0;nxt[n+1]=n+1;nxt[0]=1;pre[n+1]=n;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
int now=a[i].pos;
int L=pre[now],R=nxt[now];
int l=pre[L],r=nxt[R];
if(l+1<=R-1) ans=max(ans,uuz.query(rt[l],rt[R-1],a[i].val));
if(L+1<=r-1) ans=max(ans,uuz.query(rt[L],rt[r-1],a[i].val));
nxt[pre[now]]=nxt[now];
pre[nxt[now]]=pre[now];
}
cout<<ans;
return 0;
}