#trie#洛谷 4098 JZOJ 3226 ALO

题目


分析

首先肯定会想到建一棵可持久化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);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值