枚举每个数,计算以其为次大数的最大区间,显然,只需要用这个区间的答案 对 答案进行更新即可。
找到每个数右侧、左侧第1、2个比它大的数,然后分类讨论一下即可。
找到的过程中把数sort以后,从大到小把它们的位置插入set,稍微维护一下即可。
#include<cstdio> #include<algorithm> #include<set> using namespace std; #define N 50001 #define MAXBIT 30 set<int>T; typedef set<int>::iterator ER; int root[N],ch[N*(MAXBIT+1)][2],sz[N*(MAXBIT+1)],tot; int query(int L,int R,int W)//询问a[L...R]中W与其的最大异或值 { int ans=0; L=root[L-1];R=root[R]; for(int i=MAXBIT-1;i>=0;--i) { int Bit=(W>>i&1^1); if(sz[ch[R][Bit]]-sz[ch[L][Bit]]==0) Bit^=1; else ans+=1<<i; R=ch[R][Bit]; L=ch[L][Bit]; } return ans; } void add(int now,int W)//先add(0,0),再add(1...n,a[1...n]) { int old=root[now-1]; root[now]=++tot; now=root[now]; for(int i=MAXBIT-1;i>=0;--i) { int Bit=(W>>i&1); sz[now]=sz[old]+1; ch[now][Bit^1]=ch[old][Bit^1]; ch[now][Bit]=++tot; now=ch[now][Bit]; old=ch[old][Bit]; } sz[now]=sz[old]+1; } int n,ans,b[N],Ls[N],LLs[N],Rs[N],RRs[N]; struct Point{int x,y;}; bool operator < (const Point &a,const Point &b){return a.x<b.x;} Point a[N]; int main() { scanf("%d",&n); add(0,0); for(int i=1;i<=n;++i) { scanf("%d",&a[i].x); add(i,a[i].x); a[i].y=i; b[i]=a[i].x; } sort(a+1,a+n+1); for(int i=n;i>=1;--i) { T.insert(a[i].y); ER it=T.find(a[i].y); if(it!=T.begin()) { --it; Ls[a[i].y]=*it; if(it!=T.begin()) { --it; LLs[a[i].y]=*it; ++it; } ++it; } if((++it)!=T.end()) { Rs[a[i].y]=*it; if((++it)!=T.end()) RRs[a[i].y]=*it; else RRs[a[i].y]=n+1; } else Rs[a[i].y]=RRs[a[i].y]=n+1; } for(int i=1;i<=n;++i) { if(Ls[i]) ans=max(ans,query(LLs[i]+1,Rs[i]-1,b[i])); else if(RRs[i]!=n+1) ans=max(ans,query(1,RRs[i]-1,b[i])); if(Rs[i]!=n+1) ans=max(ans,query(Ls[i]+1,RRs[i]-1,b[i])); else if(LLs[i]) ans=max(ans,query(LLs[i]+1,n,b[i])); } printf("%d\n",ans); return 0; }
时间: 2024-10-01 00:22:11