BZOJ - 3166 可持久化Trie 维护次大区间
题意:给出\(a[1...n]\),找出一个连续区间\(a[l...r],r>l\),令该区间的次大值为\(a_k\),使得\(a_k⊕a_i,l≤i≤r\)最大,输出全局最优解
(这题意有点别扭)
异或这种套路,一般都是上trie,区间异或就加个可持久化
但问题是怎么找区间
不妨令每一个\(a_i\)为当前区间的次大值,那我们的目标就是尽可能找出该次大值的最远左右边界
令\(a_i\)从大到小插入,使用平衡树动态维护位置,那么\(pos_i\)的前驱和后继都是比\(a_i\)大的值的下标
假设第一个比\(a_i\)大的左边界下标是\(L1\),第二个比它大的是\(L2\),既\(L2<L1\)
同理设\(R2>R1\)
那么符合条件的极大区间就是\([L1+1,R2-1]\)和\([L2+1,R1-1]\)
对于字典树上求异或最大值并不需要严格区分两个极大区间,那么我们直接求出\([L2+1,R2-1]\)的异或最大值即可
PS.这回代码写着有点飘
#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define iter(i,j) for(int i=0;i<(j).size();i++)
#define print(a) printf("%lld",(ll)a)
#define println(a) printf("%lld\n",(ll)a)
#define printbk(a) printf("%lld ",(ll)a)
#define IOS ios::sync_with_stdio(0)
using namespace std;
const int MAXN = 5e4+11;
const int oo = 0x3f3f3f3f;
typedef long long ll;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int T[MAXN],a[MAXN],b[MAXN];
struct TRIE{
int tot;
int son[MAXN*35][2],size[MAXN*35];
void init(){
tot=0;
son[0][0]=son[0][1]=size[0]=0;
memset(T,0,sizeof T);
}
int insert(int old,int val){
int rt,o;rt=o=++tot;
rrep(i,30,0){
son[o][0]=son[old][0],
son[o][1]=son[old][1];
size[o]=size[old]+1;
int wh=val>>i&1;
son[o][wh]=++tot;
old=son[old][wh];
o=son[o][wh];
}
size[o]=size[old]+1;
return rt;
}
int query(int l,int r,int val){
int ans=0;
rrep(i,30,0){
int wh=val>>i&1;
if(size[son[r][wh^1]]-size[son[l][wh^1]]){
ans|=(1<<i),r=son[r][wh^1],l=son[l][wh^1];
}else{
r=son[r][wh],
l=son[l][wh];
}
}
return ans;
}
}trie;
struct QAQ{
int pos;ll val;
bool operator<(const QAQ &ORZ)const{
return val>ORZ.val;
}
}c[MAXN];
int main(){
int n,m;
while(cin>>n){
trie.init();
rep(i,1,n) c[i]=(QAQ){i,read()};
rep(i,1,n) T[i]=trie.insert(T[i-1],c[i].val);
set<int> s;
int orz[]={-1,-2,-3,oo,oo+1,oo+2};
rep(i,0,5) s.insert(orz[i]);
sort(c+1,c+1+n);
int ans=0;
rep(i,1,n){
int l,r,now;;
s.insert(l=r=now=c[i].pos);
if(i==1) continue;
set<int>::iterator it,old;
it=old=s.find(now);
it--;it--; l=(*it)+1;
it=old;
it++;it++; r=(*it)-1;
l=max(1,l);r=min(r,n);
ans=max(ans,trie.query(T[l-1],T[r],c[i].val));
}
println(ans);
}
return 0;
}