bzoj3166: [Heoi2013]Alo【可持久化线段树】

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维护前驱后继位置即可。
然后上可持久化trie树按位贪心找就可以了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=50005,INF=0x3f3f3f3f;
struct node{int cnt,son[2];}tr[N*35];
struct node1{int val,pos;}a[N];
inline bool operator < (const node1 &a,const node1 &b){return a.val>b.val;}
int n,tot,ans,rt[N];
set<int>S;
set<int>::iterator it1,it2;

void Insert(int y,int &x,int v,int dep)
{
    tr[x=++tot]=tr[y],tr[x].cnt++;
    if(dep<0)return;
    int t=(v>>dep)&1;
    Insert(tr[y].son[t],tr[x].son[t],v,dep-1);
}

int query(int x,int y,int v,int res,int dep)
{
    if(dep<0)return res;
    int t=(v>>dep)&1,dl=tr[tr[x].son[t^1]].cnt,dr=tr[tr[y].son[t^1]].cnt;
    if(dr-dl)return query(tr[x].son[t^1],tr[y].son[t^1],v,res|(1<<dep),dep-1);
    else return query(tr[x].son[t],tr[y].son[t],v,res,dep-1);
}

int main()
{
    n=getint();
    for(int i=1;i<=n;i++)a[i].val=getint(),a[i].pos=i,Insert(rt[i-1],rt[i],a[i].val,30);
    sort(a+1,a+n+1);
    S.insert(-1),S.insert(-2),S.insert(INF),S.insert(INF+1),S.insert(a[1].pos);
    for(int i=2;i<=n;i++)
    {
        it1=it2=S.upper_bound(a[i].pos);
        int l=(*--(--it1))+1,r=(*++it2)-1;
        l=max(1,l),r=min(r,n);
        if(l!=r)ans=max(ans,query(rt[l-1],rt[r],a[i].val,0,30));
        S.insert(a[i].pos);
    }
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值