【题目地址】
- 题目大意
给你 n n n个互不相同的非负数,你可以选择一个区间 l , r l,r l,r,这个区间的价值为该区间的次大值异或上该区间的另外一个值的最大值,求价值最大的区间。
显然考虑一个值异或一个区间的值的最大,我们可以用可持久化trie树解决。
但是不可能 n 2 n^2 n2枚举区间,所以我们考虑对于两个次大值相同的区间 l 1 ∼ r 1 , l 2 ∼ r 2 l_1\sim r_1,l_2\sim r_2 l1∼r1,l2∼r2,如果 l 1 ∼ r 1 l_1\sim r_1 l1∼r1包含了 l 2 ∼ r 2 l_2\sim r_2 l2∼r2,那么 l 1 ∼ r 1 l_1\sim r_1 l1∼r1的价值显然大于等于被包含的区间的价值,所以对于每个值,我们求出当它为次大值的时候的最大区间。
考虑用主席树,我们先顺着处理 l l l,然后倒着处理 r r r,对于 l l l,就是前面比它大的值的最大位置的前面比它大的值最大位置(也就是求两次),后面同理。
比如对于 v i v_i vi,在 1 ∼ i − 1 1\sim i-1 1∼i−1中比它大的值的最大位置为 j j j,那么在 1 ∼ j − 1 1\sim j-1 1∼j−1中比它大的值的最大位置为 k k k,那么 v i v_i vi的左区间就是 k + 1 k+1 k+1,右区间去最小位置即可。
先预处理和建trie树,复杂度为 O ( n l o g n + n l o g v ) O(nlogn+nlogv) O(nlogn+nlogv),然后查询复杂度为 O ( n l o g v ) O(nlogv) O(nlogv)
有更简单的做法,我的做法比较麻烦
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=2e6+10,N=5e4+10,inf=1e9+7;
int n,val[N],lg,MAXV,bin[32];
int son[M][2],root[N],cnt[M],tot;
void build(int last,int &now,int v){
if(!now)now=++tot;
int a=now,b=last,idx;
for(int i=lg;i>=0;i--){
idx=(v>>i)&1;
son[a][idx^1]=son[b][idx^1];
cnt[son[a][idx]=++tot]=cnt[son[b][idx]]+1;
a=son[a][idx];b=son[b][idx];
}
}
int query(int v,int l,int r){
if(l>r) return 0;
int a=0,idx,L=root[l],R=root[r];
for(int i=lg;i>=0;i--){
idx=(v>>i)&1;
if(cnt[son[L][idx^1]]<cnt[son[R][idx^1]]){
a|=bin[i];
L=son[L][idx^1];R=son[R][idx^1];
}else{
L=son[L][idx];R=son[R][idx];
}
} return a;
}
int befmax[M],aftmax[M];
namespace Pre{
int pos[M],ls[M],rs[M],tot,type;
int root[N];
void clear(){
memset(root,0,sizeof(root));
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
memset(pos,0,sizeof(pos));tot=0;
}
void pushup(int o){
if(type)pos[o]=max(pos[ls[o]],pos[rs[o]]);
else pos[o]=min(pos[ls[o]],pos[rs[o]]);
}
void insert(int pre,int &o,int l,int r,int p,int v){
o=++tot;ls[o]=ls[pre];rs[o]=rs[pre];pos[o]=type?0:inf;
if(l==r){pos[o]=v;return;}
int mid=l+r>>1;
if(p<=mid) insert(ls[pre],ls[o],l,mid,p,v);
else insert(rs[pre],rs[o],mid+1,r,p,v);
pushup(o);
}
int query(int o,int l,int r,int L,int R){
if(!o) return type?-1:n+1;
if(L<=l&&r<=R) return pos[o];
int mid=l+r>>1;
if(R<=mid) return query(ls[o],l,mid,L,R);
if(L>mid) return query(rs[o],mid+1,r,L,R);
if(type) return max(query(ls[o],l,mid,L,R),query(rs[o],mid+1,r,L,R));
else return min(query(ls[o],l,mid,L,R),query(rs[o],mid+1,r,L,R));
}
int lsv[N],Cnt;
int Bef(int p,int id){
int p1=query(root[p-1],1,Cnt,id,Cnt);
if(p1>1){
int p2=query(root[p1-1],1,Cnt,id,Cnt);
if(~p2)befmax[p]=p2+1;
else befmax[p]=1;
}else{
befmax[p]=1;
}
}
int Aft(int p,int id){
int p1=query(root[p+1],1,Cnt,id,Cnt);
if(p1<=n){
int p2=query(root[p1+1],1,Cnt,id,Cnt);
if(p2<=n)aftmax[p]=p2-1;
else aftmax[p]=n;
}else{
aftmax[p]=n;
}
} int P[N];
void init(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);lsv[i]=val[i];
if(val[i]>MAXV)MAXV=val[i];
} for(lg=1;(1ll<<lg)<=MAXV;++lg);
bin[0]=1;for(int i=1;i<=lg;i++)bin[i]=bin[i-1]<<1;
sort(lsv+1,lsv+n+1);Cnt=unique(lsv+1,lsv+n+1)-lsv-1;
type=1;for(int i=1;i<=n;i++){
P[i]=lower_bound(lsv+1,lsv+Cnt+1,val[i])-lsv;
Bef(i,P[i]);
insert(root[i-1],root[i],1,Cnt,P[i],i);
} clear();
type=0;pos[0]=inf;for(int i=n;i>=1;i--){
Aft(i,P[i]);
insert(root[i+1],root[i],1,Cnt,P[i],i);
}
}
}
int main(){
Pre::init();int ans=0,now;
for(int i=1;i<=n;i++)
build(root[i-1],root[i],val[i]);
for(int i=1;i<=n;i++){
if(val[i]==MAXV) continue;
now=query(val[i],befmax[i]-1,aftmax[i]);
if(now>ans)ans=now;
} printf("%d\n",ans);
return 0;
}