题目描述:
现在你拥有 n 颗宝石,每颗宝石有一个能量密度,记为 ai,这些宝石的能量 密度两两不同。现在你可以选取连续的一些宝石(必须多于一个)进行融合,设 为 ai, ai+1, …, aj,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值 与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值 为 k,则生成的宝石的能量密度为 max{k xor ap | ap ≠ k , i ≤ p ≤ j}
题解:
首先建可持久化Trie。
然后是区间的选取问题。
想了好久想出来一种方法:
对于每个点建双向链表,从小到大删点。
对于每个点可取区间为[左方第二个比它大的+1,右方第二个比它大的-1]。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 50050 inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,a[N]; struct Trie { int tot,siz[32*N],ch[32*N][2],rt[N]; void insert(int k,int x) { int u,l=rt[k-1]; rt[k]=u=++tot; for(int i=30;i>=0;i--) { ch[u][0]=ch[l][0],ch[u][1]=ch[l][1],siz[u]=siz[l]+1; int k = (x>>i)&1; ch[u][k]=++tot; u=ch[u][k],l=ch[l][k]; } siz[u]=siz[l]+1; } int query(int l,int r,int x) { l = rt[l],r = rt[r]; int ret = 0; for(int i=30;i>=0;i--) { int k = (x>>i)&1; if(siz[ch[r][!k]]-siz[ch[l][!k]]) { l=ch[l][!k],r=ch[r][!k]; ret|=(1<<i); }else l=ch[l][k],r=ch[r][k]; } return ret; } }tr; int l[N],r[N],lf[N],rg[N]; struct node { int x,v; }p[N]; bool cmp(node a,node b) { return a.v<b.v; } int main() { n=rd(); for(int i=1;i<=n;i++) { a[i]=rd(),l[i]=i-1,r[i]=i+1; tr.insert(i,a[i]); p[i].x=i,p[i].v=a[i]; } l[0]=0,r[0]=1; l[n+1]=n,r[n+1]=n+1; int ans = 0; sort(p+1,p+1+n,cmp); for(int i=1;i<=n;i++) { int u = p[i].x; r[l[u]]=r[u],l[r[u]]=l[u]; lf[u]=l[l[u]],rg[u]=r[r[u]]; } for(int i=1;i<=n;i++) ans=max(ans,tr.query(lf[i],rg[i]-1,a[i])); printf("%d\n",ans); return 0; }