zoukankan      html  css  js  c++  java
  • 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;    
    }
  • 相关阅读:
    Euraka适合初学者的简单小demo
    springboot中常用的依赖
    SpringBoot的入门程序
    spring-data-solr查询
    SpringBoot整合Redis
    SpringBoot整合MyBatis
    使用swagger2生成文档
    SpringBoot整合Spring Data JPA
    SpringBoot构建RESTful API
    SpringBoot属性配置
  • 原文地址:https://www.cnblogs.com/five20/p/9727949.html
Copyright © 2011-2022 走看看