Evanyou Blog 彩带

P4098 [HEOI2013]ALO

 

题目描述

 

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}

 

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

 

输入输出格式

输入格式:

 

 

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

 

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

 

 

输出格式:

 

 

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

 

 

 

输入输出样例

 

输入样例#1: 
5 
9 2 1 4 7
输出样例#1: 
14

 

说明

 

【样例解释】

 

选择区间[1,5],最大值为 7 xor 9

 

【数据规模与约定】

 

对于 20%的数据有 n ≤ 100

 

对于 50%的数据有 n ≤ 2000

 

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

 

 

Solution:

  本题可持久化trie树+平衡树。

  题意就是随便一个长度大于1的区间,用区间中的某一值异或区间次大值,求该值最大是多少。

  先用可持久化trie数维护每个权值,再考虑枚举每个数作为次大值的情况,那么我们需要确定的就是以该数作为次大值,覆盖的区间$[l,r]$最大是多少,就可以直接在trie树上贪心了。

  于是解题关键就是如何快速的求每个数作为次大值,覆盖的最大区间$[l,r]$。

  我们可以把数从大到小排序,然后用平衡树维护每个数的下标,初始时树为空,我们可以先往树中插入一个$0$和$n+1$作为区间限制。

  按排序后的顺序枚举每个数作为次大值,对于数$a_i$,设其原下标为$k$,因为我们是按权值从大到小把下标加入平衡树,那么就可以保证此时平衡树中的下标所代表的值都大于$a_i$,而平衡树所维护的是每个数的下标,所以直接查询$k$的前驱的前驱$l$,和$k$的后继的后继$r$,那么就能确定以$a_i$为次大值的最大区间范围为$[l+1,r-1]$了。(实现时有很多细节需要注意)

代码:

/*Code by 520 -- 9.29*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define son(x) (x==ch[fa[x]][1])
using namespace std;
const int N=50005;
int n,cnt,rt[N];
struct num{
    int v,id;
    bool operator < (const num &a) const {return v>a.v;}    
}a[N];
struct node{
    int son[2],tot;    
}t[N*50];

int gi(){
    int a=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;
}

struct fhq_treap{
    int root,cnt,date[N],ch[N][2],rnd[N],siz[N];
    il void clr(){
        cnt=root=0,memset(ch,0,sizeof(ch)),memset(date,0,sizeof(date));    
    }
    il int newnode(int v){
        ++cnt;
        siz[cnt]=1,date[cnt]=v,rnd[cnt]=rand();
        return cnt;
    }
    il void up(int rt){siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1;}
    int merge(int x,int y){
        if(!x||!y) return x+y;
        if(rnd[x]<rnd[y]) {ch[x][1]=merge(ch[x][1],y),up(x);return x;}
        else {ch[y][0]=merge(x,ch[y][0]),up(y);return y;}
    }
    void split(int rt,int k,int &x,int &y){
        if(!rt) {x=0,y=0;return;}
        if(date[rt]<=k) x=rt,split(ch[rt][1],k,ch[x][1],y),up(x);
        else y=rt,split(ch[rt][0],k,x,ch[y][0]),up(y);    
    }
    il void ins(int v){
        int x=0,y=0; split(root,v,x,y);
        root=merge(merge(x,newnode(v)),y);
    }
    il int kth(int rt,int v){
        if(!v) return 0;
        while(1){
            if(siz[ch[rt][0]]>=v) rt=ch[rt][0];
            else if(siz[ch[rt][0]]+1<v) v-=siz[ch[rt][0]]+1,rt=ch[rt][1];
            else return date[rt];    
        }
    }
    il int pre(int v){
        int x=0,y=0,ans; split(root,v-1,x,y);
        ans=kth(x,siz[x]); root=merge(x,y);
        return ans;
    }
    il int suc(int v){
        int x=0,y=0,ans; split(root,v,x,y);
        ans=kth(y,1); root=merge(x,y);
        return ans;    
    }
}T;

void ins(int &rt,int lst,int d,int v){
    t[rt=++cnt]=t[lst],t[rt].tot++;
    if(d<0)    return;
    int p=v&(1<<d)?1:0;
    ins(t[rt].son[p],t[lst].son[p],d-1,v);
}

int query(int l,int r,int d,int v,int ans){
    if(d<0) return ans;
    int p=v&(1<<d)?1:0,ls=t[t[l].son[p^1]].tot,rs=t[t[r].son[p^1]].tot;
    if(rs-ls) return query(t[l].son[p^1],t[r].son[p^1],d-1,v,ans|(1<<d));
    return query(t[l].son[p],t[r].son[p],d-1,v,ans);    
}

int main(){
    srand(time(0));
    n=gi();
    For(i,1,n) a[i].v=gi(),a[i].id=i,ins(rt[i],rt[i-1],30,a[i].v);
    sort(a+1,a+n+1);
    int l,r,lp,rp,ans=query(rt[0],rt[n],30,a[2].v,0); T.clr();
    T.ins(a[1].id),T.ins(a[2].id),T.ins(n+1);
    For(i,3,n) {
        l=T.pre(a[i].id),r=T.suc(a[i].id);
        if(!l) l=1; else l=T.pre(l)+1;
        if(r>n) r=n; else r=T.suc(r)-1;
        if(r-l) ans=max(ans,query(rt[l-1],rt[r],30,a[i].v,0));
        T.ins(a[i].id);
    }
    cout<<ans;
    return 0;    
}

 

posted @ 2018-09-30 09:22  five20  阅读(263)  评论(0编辑  收藏  举报
Live2D