3226. 【HBOI2013】ALO

Description

Welcome to ALO ( Arithmetic and Logistic Online)。这是一个VR MMORPG,如名字所见,到处充满了数学的谜题。

现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同。现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为ai, ai+1, …, aj,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值的最大值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密度为max{k xor ap | ap ≠ k , i ≤ p ≤ j}。

现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最大。

Input

第一行,一个整数n,表示宝石个数。

第二行,n个整数,分别表示a1至an,表示每颗宝石的能量密度,保证对于i ≠ j有ai ≠ aj。

Output

输出一行一个整数,表示最大能生成的宝石能量密度。

Sample Input

5

9 2 1 4 7

Sample Output

14

Data Constraint

对于20%的数据有n ≤ 100。

对于50%的数据有n ≤ 2000。

对于100%的数据有1 ≤ n ≤ 50000, 0 ≤ ai ≤ 10^9。

Hint

样例解释:选择区间[1,5],最大值为7 xor 9。

Solution

考试时想出来了可持久化Trie,但是没有想到如何求离当前点最近的比当前点大的第二个位置。

首先枚举次大值。

预处理出次大值前面的第一个比它大的位置(记为l[ i ]),第二个比它大的位置(记为L[ i ])。

以及后面第一个比它大的位置(记为r[ i ]),第二个比它大的位置(记为R[ i ])。

那么答案即为区间(l[ i ]+1~R[ i ]-1)以及(L[ i ]+1~r[ i ]-1)的最大值。

建立一棵可持久化Trie,对于区间直接询问异或最大值即可。

扫描二维码关注公众号,回复: 11655641 查看本文章

假设我们已经求出来了l[]和r[],

那么对于每个位置记录fir[x]表示它后面第一个l[fir[x]]=x即比x小的离x最近的l[]等于x的点。(设为y)

那么每次从x-1往前跳l指针,知道找到一个比y大的点,那么L[y]=x。同时y不断跳r[y]并保证a[y]<a[x]

对于R[y]同理。

时间复杂度最多为log

总时间复杂度O(n log n)。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(register I i=a;i<=b;i++)
#define Fd(i,a,b) for(register I i=a;i>=b;i--)
#define N 50002
using namespace std;
I n,a[N],l[N],r[N],L[N],R[N],s[N],fir[N],las[N],tp,cnt,A[N],tr[N*31][2],bz[N*31],rt[N],tot,ans;
struct node{I v,id;}o[N];
I cmp(node x,node y){return x.v<y.v;}
void ins(I x,I y,I s){
	Fd(i,29,0){
		bz[x]=bz[y]+1;
		if((s>>i)&1){
			if(!tr[x][1]) tr[x][1]=++tot;
			tr[x][0]=tr[y][0],x=tr[x][1],y=tr[y][1];
		}
		else{
			if(!tr[x][0]) tr[x][0]=++tot;
			tr[x][1]=tr[y][1],x=tr[x][0],y=tr[y][0];
		}
	}
	bz[x]=bz[y]+1;
}
I qry(I x,I y,I s){
	I sum=0,k;
	Fd(i,29,0){
		k=(s>>i)&1;
		if(bz[tr[y][!k]]-bz[tr[x][!k]]){sum+=1<<i;y=tr[y][!k],x=tr[x][!k];}
		else{x=tr[x][k],y=tr[y][k];}
	}
	return sum;
}
I main(){
	freopen("ALO.in","r",stdin);
	freopen("ALO.out","w",stdout);
	scanf("%d",&n);
	F(i,1,n){
		scanf("%d",&a[i]);
		ins(rt[i]=++tot,rt[i-1],a[i]);
		o[i]=node{a[i],i};
	}
	sort(o+1,o+1+n,cmp);
	F(i,1,n){A[o[i].id]=(cnt+=(o[i].v!=o[i-1].v));}
	F(i,1,n){
		while(tp&&a[s[tp]]<a[i]) tp--;
		l[i]=s[tp];
		if(!fir[l[s[++tp]=i]]) fir[l[i]]=i;
	}
	s[tp=0]=n+1;
	Fd(i,n,1){
		while(tp&&a[s[tp]]<a[i]) tp--;
		r[i]=s[tp];
		if(!las[r[s[++tp]=i]])  las[r[i]]=i;
	}
	/*F(i,1,n){
		Fd(j,l[i]-1,1) if(a[j]>a[i]){
			L[i]=j;break;
		}
		R[i]=n+1;
		F(j,r[i]+1,n) if(a[j]>a[i]){
			R[i]=j;break;
		}
	}*/
	F(i,1,n) if(fir[i]){
		for(register I j=fir[i],k=i-1;k&&j<=n&&l[j]==i;j=r[j]){
			while(k&&a[k]<a[j]) k=l[k];
			if(k) L[j]=k;else break;
		}
		/*x=i-1,y=fir[i];
		while(y<=n){
			if(l[y]!=i) break;
			while(x&&a[x]<a[y]) x=l[x];
			if(!x) break;
			L[y]=x,y=r[y];
		}*/
	}
	Fd(i,n,1) if(las[i]){
		for(register I j=las[i],k=i+1;k&&j&&r[j]==i;j=l[j]){
			while(k<=n&&a[k]<a[j]) k=r[k];
			if(k<=n) R[j]=k;else break;
		}
		/*I x=i+1,y=las[i];
		while(y){
			if(r[y]!=i) break;
			while(x<=n&&a[x]<a[y]) x=r[x];
			if(x>n) break;
			R[y]=x,y=l[y];
		}*/
	}
	F(i,1,n){
		if(r[i]) ans=max(ans,qry(rt[L[i]],rt[r[i]-1],a[i]));
		if(R[i]) ans=max(ans,qry(rt[l[i]],rt[R[i]-1],a[i]));
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/107801361