您的位置:首页 > 其它

[BZOJ3166][Heoi2013]Alo 可持久化Trie树

2017-08-03 21:02 513 查看

3166: [Heoi2013]Alo

Time Limit: 20 Sec Memory Limit: 256 MB

Description
Welcome to ALO ( Arithmetic and Logistic Online)。这是一个VR MMORPG ,
如名字所见,到处充满了数学的谜题。
现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量
密度两两不同。现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为 ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值
与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值
为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
HINT
【样例解释】
选择区间[1,5],最大值为 7 xor 9。
对于 100%的数据有 1 ≤ n ≤ 50000, 0 ≤ ai ≤ 10^9

题解:

我们不难想到在单调队列题目中用过的一种思路:枚举每个点作为次小值,去找比他大的值,那么能满足题目要求的区间大概长这样:



上图中两端被扩起来的区间即为所求。那么现在我们的问题转化为去找每个点从左从右数第二个比他大的值的位置。

这个显然不能用单调队列搞……

由于题目保证每一个数据都不相等,所以我们考虑搞一个set,把数据按权值大小排序,然后插入元素的下标。

由于在插入某个值的时候,比他大的都已经插入了

所以这个时候查询比他大2名的和小2名的即可。

具体实现有一些边界处理的小细节,读者可以结合下面代码思考一下。代码见下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
const int N=50100;
struct Trie
{
Trie *ch[2];int size;
Trie(){ch[0]=ch[1]=0,size=0;}
}*null=new Trie(),*root
;
inline Trie* newTrie(){Trie *o=new Trie();o->ch[0]=o->ch[1]=null;return o;}
int cnt,stack
,top;LL bin[40];
set<int>st;
struct node{int pos,val;}a
;
inline bool mt(const node &a,const node &b){return a.val>b.val;}
void Insert(Trie *&o,Trie *old,int val,int i)
{
if(i<0)return;
int d=((val&bin[i])==bin[i]);
o->ch[d]=newTrie(),o->ch[d^1]=old->ch[d^1];
o->ch[d]->size=old->ch[d]->size+1;
Insert(o->ch[d],old->ch[d],val,i-1);
}
inline int query(int a,int b,int val)
{
int ret=0;
Trie *x=root[a],*y=root[b];
for(int i=30;~i;i--)
{
int d=(val&bin[i])>>i;
if(y->ch[d^1]->size-x->ch[d^1]->size)
ret|=bin[i],y=y->ch[d^1],x=x->ch[d^1];
else y=y->ch[d],x=x->ch[d];
}
return ret;
}
int main()
{
int n;scanf("%d",&n);
bin[0]=1;for(int i=1;i<=35;i++)bin[i]=bin[i-1]<<1;
for(int i=0;i<=n;i++)root[i]=newTrie();
null->ch[0]=null->ch[1]=null;
for(int i=1;i<=n;i++)
scanf("%d",&a[i].val),a[i].pos=i,Insert(root[i],root[i-1],a[i].val,30);
sort(a+1,a+n+1,mt);
st.insert(-1);st.insert(-2);st.insert(-3);
st.insert(n+1);st.insert(n+2);st.insert(n+3);
st.insert(a[1].pos);
int ans=0;
for(int i=2;i<=n;i++)
{
set<int>::iterator a1,a2;
a2=st.lower_bound(a[i].pos);
a1=a2;a2++;a1--;a1--;
int l=*a1+1,r=*a2-1;
l=max(l,1),r=min(n,r);
ans=max(ans,query(l-1,r,a[i].val));
st.insert(a[i].pos);
}
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: