[Heoi2013]Alo
[Heoi2013]Alo
每一个点作为贡献点的区间是包含一个比它大的值,所以我们对于每个点处理四个值
\(L,R,L2,R2\)表示左边第一个比它大的,右边第一个,左边第二个,右边第二个~
这些东西当然可以直接用set处理,但是可以前缀预处理+两边二分替换,甚至是第一遍二分也可以用单调栈代替,能跑得快一些
那么这个点最大的可能贡献的区间就是\([L2+1,R-1]\),\([L+1,R2-1]\)
接下来的问题就是对于一个值\(x\),求区间内的数与它的最大异或,这个我们用可持久化\(trie\)树等奇怪的数据结构实现
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define reg register
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
char IO;
int rd(){
int s=0,f=0;
while(!isdigit(IO=getchar())) if(IO=='-') f=1;
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
const int N=5e4+10;
bool be;
int n;
int a[N];
int rt[N],nxt[N*32][2];
int m,s[N*32];
void Pre_Make() {
rep(i,1,n) {
int p,pre=rt[i-1];
p=rt[i]=++m;
drep(j,29,0) {
int x=((a[i]>>j)&1);
nxt[p][x]=++m;
nxt[p][!x]=nxt[pre][!x];
p=nxt[p][x],pre=nxt[pre][x];
s[p]=s[pre]+1;
}
}//预处理可持久化trie
}
int ans;
void Que(int x,int l,int r) {
l=rt[l-1],r=rt[r];
int res=0;
drep(i,29,0) {
int t=(x&(1<<i))>0;
if(s[nxt[r][!t]]-s[nxt[l][!t]]>0) res|=1<<i,l=nxt[l][!t],r=nxt[r][!t];
else l=nxt[l][t],r=nxt[r][t];
}
ans=max(ans,res);//贪心查询
}
int stk[N],top;
int L[N],R[N],LL[N],RR[N]; // LL=L2,RR=R2
struct Node{
int x,id,t;
bool operator < (const Node __) const {
return id<__.id;
}
}B[N];
int cmp(const Node x,const Node y){
return x.id>y.id;
}
int cnt;
bool ed;
int main(){
n=rd();
rep(i,1,n) a[i]=rd();
Pre_Make();
rep(i,1,n) {
while(top && a[stk[top]]<a[i]) top--;
L[i]=stk[top];
if(L[i]>1) B[++cnt]=(Node){a[i],L[i]-1,i};
stk[++top]=i;
}
top=0;
sort(B+1,B+cnt+1);
int p=1;//一遍单调栈+一遍二分预处理
rep(i,1,n) {
while(top && a[stk[top]]<a[i]) top--;
stk[++top]=i;
while(p<=cnt && B[p].id<=i) {
int l=1,r=top,res=0;
while(l<=r) {
int mid=(l+r)>>1;
if(a[stk[mid]]>B[p].x) l=mid+1,res=stk[mid];
else r=mid-1;
LL[B[p].t]=res;
}
p++;
}
}
top=cnt=0;
drep(i,n,1) {
while(top && a[stk[top]]<a[i]) top--;
R[i]=stk[top];
if(R[i]<n && R[i]) B[++cnt]=(Node){a[i],R[i]+1,i};
stk[++top]=i;
}
sort(B+1,B+cnt+1,cmp);
p=1;
top=0;
drep(i,n,1) {
while(top && a[stk[top]]<a[i]) top--;
stk[++top]=i;
while(p<=cnt && B[p].id>=i) {
int l=1,r=top,res=0;
while(l<=r) {
int mid=(l+r)>>1;
if(a[stk[mid]]>B[p].x) l=mid+1,res=stk[mid];
else r=mid-1;
RR[B[p].t]=res;
}
p++;
}
}
rep(i,1,n) {
if(!L[i] && !R[i]) continue;
Que(a[i],LL[i]+1,RR[i]?RR[i]-1:n);
}
printf("%d\n",ans);
}