zoukankan      html  css  js  c++  java
  • 【BZOJ3166】ALO(HEOI2013)-set+可持久化trie

    测试地址:ALO
    题目大意:给定一个数列A,每项各不相同,令一个区间的价值为:区间中的次大值与区间中某个其它元素异或起来能得到的最大值,求最大的区间价值。
    做法:本题需要用到set+可持久化trie。
    我们知道,如果一个元素是次大值,那么我们肯定希望找到以这个元素为次大值的极大区间(即向左右任何一边扩展都不能满足条件的区间),这样就更有机会凑出更大的价值。以这个元素为次大值,等价于区间中存在且仅存在一个比它大的数字,那么显然这个元素不能是数列中最大的元素。然后我们找到这个元素左右离它最近的比它大的元素所处的位置,记为l1,r1,再找到这个元素左右离它第二近的比它大的元素所处的位置,记为l2,r2,不难发现以该元素为次大值的极大区间有两个:[l1+1,r21][l2+1,r11]。因此我们从大到小插入数列中的元素,然后用set维护求出上面那些位置(或者从小到大删除数列中的元素,用双向链表维护求出,这里本人偷懒使用了STL),就可以得到极大区间了。可以知道这样的区间至多有2n个。
    那么现在问题就变成求一个区间中某个元素和某个给定的数异或起来能得到的最大值。我们把每个元素二进制分解,就成了一个01串,如果我们能想办法快速求出一个区间中所有串组成的trie,我们就可以贪心求解了。这时我们类比可持久化线段树,建一棵可持久化trie,这样就可以提取出对应的区间了。
    以上算法的时间复杂度为O(nlogn),可以通过此题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,ch[2000010][2]={0},rt[50010]={0},siz[2000010]={0};
    int tot;
    set<int> S;
    set<int>::iterator it;
    struct forsort
    {
        int pos,val;
    }f[50010];
    
    void pushup(int v)
    {
        siz[v]=siz[ch[v][0]]+siz[ch[v][1]];
    }
    
    void insert(int last,int &v,int step,int x)
    {
        v=++tot;
        siz[v]=siz[last];
        ch[v][0]=ch[last][0];
        ch[v][1]=ch[last][1];
        if (step<0)
        {
            siz[v]++;
            return;
        }
        if (x&(1<<step)) insert(ch[last][1],ch[v][1],step-1,x);
        else insert(ch[last][0],ch[v][0],step-1,x);
        pushup(v);
    }
    
    int query(int l,int r,int step,int x)
    {
        if (step<0) return 0;
        if (x&(1<<step))
        {
            if (siz[ch[r][0]]-siz[ch[l][0]]>0)
                return (1<<step)+query(ch[l][0],ch[r][0],step-1,x);
            else return query(ch[l][1],ch[r][1],step-1,x);
        }
        else
        {
            if (siz[ch[r][1]]-siz[ch[l][1]]>0)
                return (1<<step)+query(ch[l][1],ch[r][1],step-1,x);
            else return query(ch[l][0],ch[r][0],step-1,x);
        }
    }
    
    bool cmp(forsort a,forsort b)
    {
        return a.val>b.val;
    }
    
    void init()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            insert(rt[i-1],rt[i],31,x);
            f[i].pos=i,f[i].val=x;
        }
    
        sort(f+1,f+n+1,cmp);
    }
    
    int findans(int l,int r,int x)
    {
        return query(rt[l-1],rt[r],31,x);
    }
    
    void work()
    {
        S.insert(0);
        S.insert(n+1);
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            int l1,l2,r1,r2;
            it=S.lower_bound(f[i].pos);
            r1=(*it);
            it++;
            if (it!=S.end()) r2=(*it);
            else r2=r1;
            it--;it--;
            l1=(*it);
            if (it!=S.begin()) it--,l2=(*it);
            else l2=l1;
            S.insert(f[i].pos);
            if (i>1) ans=max(ans,max(findans(l2+1,r1-1,f[i].val),findans(l1+1,r2-1,f[i].val)));
        }
        printf("%d",ans);
    }
    
    int main()
    {
        init();
        work();
    
        return 0;
    }
  • 相关阅读:
    Docker虚拟机配置手札(centos)
    Nginx配置手札
    登录的顶号功能实现
    苹果登录服务端JWT算法验证-PHP
    mac Read-Only filesystem (转载)
    ssh公私钥登录/git公私钥认证
    crontab 定时访问指定url,定时脚本
    网站通用 敏感词列表
    游戏行业术语一览(2)--游戏运营转化率[转载]
    <转载>为什么VR不可能成功?
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793442.html
Copyright © 2011-2022 走看看