题解 P4098 【[HEOI2013]ALO 】
Youngsc
%% 楼下大佬暴力水过
身为蒟蒻的我暴力写挂了,就码了一发可持久化权值字典树
可持久化权值字典树和可持久化的权值线段树非常类似,会写主席树就能码出来可持久化trie
我们枚举每一个值作为次大值的情况
不妨设当前数字左边第一个比它大的下标为
同理设当前数字右边第一个比它大的下标为
那么对于一个数字来说,它能作为次大值的区间有很多,但我们只取两个区间
分别是
要处理这个的话我们可以借助链表,将元素按照从小到大的顺序依次删除
每次删除之前当前位置左右一共四个元素就是上述的四个元素
当然,如果一个元素左边没有比他大的或者右边没有比他 大的就需要特判
然后就在区间内的trie上贪心的从高位到低位取反
# include <bits/stdc++.h>
# define R register
# define N 50010
# define inf 2000101900
using namespace std;
int n,a[N],t[N*35],ch[N*35][2],ans,pre[N],nxt[N],rt[N],cnt;
pair <int,int> b[N];
template <typename T> inline void in(R T &a){
R char c = getchar();R T x=0,f=1;
while(!isdigit(c)) {if(c == '-') f=-1; c=getchar();}
while(isdigit(c)) x=(x<<1)+(x<<3)+c-'0',c = getchar();
a=x*f;
}
template <typename T> inline void maxx(R T& a,const T b){a<b ? a=b:0;}
template <typename T> inline void minn(R T& a,const T b){a>b ? a=b:0;}
inline void insert(R int x,R int pos){
R int now = rt[pos] = ++cnt,las = rt[pos-1];
t[now] = t[las]+1;
for (R int i=30; i>=0; --i)
{
R int tag = x>>i&1;
ch[now][tag^1] = ch[las][tag^1];
ch[now][tag] = ++cnt;
now = ch[now][tag];
las = ch[las][tag];
t[now] = t[las]+1;
}
}
inline int qury(R int sum,R int l,R int r){
l--;
R int now = rt[l],las = rt[r],ret=0;
for (R int i=30; i>=0; --i)
{
R int tag = sum>>i&1;
if (t[ch[las][tag^1]]-t[ch[now][tag^1]])
{
ret ^= (1<<i);
now = ch[now][tag^1];
las = ch[las][tag^1];
}
else
{
now = ch[now][tag];
las = ch[las][tag];
}
}
return ret;
}
int main(){
in(n);
R int fir=0,las=n+1;
pre[las] = n,nxt[fir] = 1;
a[fir] = a[las] = inf;
for (R int i=1; i<=n; ++i) pre[i] = i-1,nxt[i] = i+1,in(a[i]),b[i] = make_pair(a[i],i),insert(a[i],i);
sort(b+1,b+n+1);\\按从小到大排序
for (R int i=1; i<=n; ++i)
{
R int x = b[i].second;
R int l = pre[x],r = nxt[x];\\取当前位置的左右两个值
nxt[l] = r,pre[r] = l;\\删除
if (l != fir) maxx(ans,qury(a[x],pre[l]+1,r-1)); \\如果左边有更大的
if (r != las) maxx(ans,qury(a[x],l+1,nxt[r]-1)); \\如果右边有更小的
}
printf("%d",ans);
}