分析
首先肯定会想到建一棵可持久化01trie,但是关键是次大值,所以考虑从小到大排序,那么每次该数都会有一段选择的区间,那么考虑把它合并给左右,用该值当次大值在trie中找到区间中最大的一个,其实这道题实际操作比理论还要难,至少我是这么认为的
代码
#include <cstdio>
#include <cctype>
#include <deque>
#include <algorithm>
#define rr register
using namespace std;
const int INF=2e9+11,N=50011; pair<int,int>b[N];
int l[N],r[N],a[N],n,cnt,root[N],ans;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
struct I_AC_the_Task{
int son[N*31],tr[N*31][2],tot;
inline void Insert(int x){
rr int rt=root[cnt];
root[++cnt]=++tot;
for (rr int i=29;~i;--i){
rr int p=(x>>i)&1;
son[tot]=son[rt]+1;
tr[tot][p]=tot+1;
tr[tot][p^1]=tr[rt][p^1];
rt=tr[rt][p],++tot;
}
son[tot]=son[rt]+1;
}
inline signed query(int l,int r,int x){
rr int ls=root[l],rs=root[r],ans=0;
for (rr int i=29;~i;--i){
rr int p=(x>>i)&1;
if (son[tr[ls][p^1]]<son[tr[rs][p^1]])
ls=tr[ls][p^1],rs=tr[rs][p^1],ans|=1<<i;
else ls=tr[ls][p],rs=tr[rs][p];
}
return ans;
}
}trie;
inline signed max(int a,int b){return a>b?a:b;}
signed main(){
n=iut(); a[0]=a[n+1]=INF; r[0]=1,l[n+1]=n; trie.tot=0;
for (rr int i=1;i<=n;++i) a[i]=iut(),l[i]=i-1,r[i]=i+1;
for (rr int i=1;i<=n;++i) b[i]=make_pair(a[i],i),trie.Insert(a[i]);
sort(b+1,b+1+n);
for (rr int i=1;i<=n;++i){
rr int pos=b[i].second,L=l[pos],R=r[pos]; l[R]=L,r[L]=R;
if (L>=1) ans=max(ans,trie.query(l[L],R-1,a[pos]));
if (R<=n) ans=max(ans,trie.query(L,r[R]-1,a[pos]));
}
return !printf("%d",ans);
}