@ysner
2018-08-04T01:32:57.000000Z
字数 1706
阅读 2104
可持久化Trie
Trie
现在你拥有颗宝石,每颗宝石有一个能量密度,记为。现在你可以选取连续的一些宝石(必须多于一个)进行融合,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值。
现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最大。
显然要可持久化树。
唯一有点费脑子的地方是次大值。
在一个区间找次大值会把复杂度弄得很鬼。
换个角度想,如果枚举次大值,则有两种情况:
实际上我们可以用链表维护大小关系。
依从小到大枚举,用完这个数就把它删掉,这样左右端就是两个比它大的数,可以确定区间左右端点。
于是分情况统计答案即可。
不加rt调1h系列
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=1e5+100;
struct dat{int w,id;bool operator < (const dat &o) const {return w<o.w;}}a[N];
int ysn,sum[N*50],t[N*50][2],l[N],r[N],ans,n,rt[N*50];
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void Build(re int x,re int &y,re int w,re int dep)
{
sum[y=++ysn]=sum[x]+1;
if(dep<0) return;
re int p=(w>>dep)&1;
t[y][p^1]=t[x][p^1];
Build(t[x][p],t[y][p],w,dep-1);
}
il int Query(re int x,re int y,re int w,re int dep)
{
if(dep<0) return 0;
re int p=(w>>dep)&1,tmp=sum[t[y][p^1]]-sum[t[x][p^1]];
if(tmp) return (1<<dep)+Query(t[x][p^1],t[y][p^1],w,dep-1);
else return Query(t[x][p],t[y][p],w,dep-1);
}
int main()
{
n=gi();
fp(i,1,n) a[i].w=gi(),a[i].id=i,l[i]=i-1,r[i]=i+1,Build(rt[i-1],rt[i],a[i].w,30);
sort(a+1,a+1+n);
fp(i,1,n)
{
re int x=a[i].id,z=l[x],y=r[x];
r[z]=y;l[y]=z;
if(z) ans=max(ans,Query(rt[l[z]],rt[y-1],a[i].w,30));
if(y<=n) ans=max(ans,Query(rt[z],rt[r[y]-1],a[i].w,30));
}
printf("%d\n",ans);
return 0;
}