bzoj3166: [Heoi2013]Alo 可持久化字典树

左右两边的比i大的最近的两个值。然后可持久化字典树即可。

#include<bits/stdc++.h>
using namespace std;
int maxn=0,n,root[1600000],a[50010],cnt=0,l[1600000],r[1600000],p1[50010][25],p2[50010][25],sum[1600000],ans=0,pans=0,l1[50010],r1[50010],l2[50010],r2[50010];
void add(int &rt,int pre,int val,int id)
{
    if(!rt)rt=++cnt;
    sum[rt]=sum[pre]+1;
    if(id<0)return;
    if(val&(1<<id))
    {
        l[rt]=l[pre];
        add(r[rt],r[pre],val,id-1);
    }
    else
    {
        r[rt]=r[pre];
        add(l[rt],l[pre],val,id-1);
    }
}
void work(int L,int R,int val,int id)
{
    if(id<0)return;
    if((1<<id)&val)
    {
        if(sum[l[R]]-sum[l[L]])
        {
            pans|=(1<<id);
            work(l[L],l[R],val,id-1);
        }
        else work(r[L],r[R],val,id-1);

    }
    else
    {
        if(sum[r[R]]-sum[r[L]])
        {
            pans|=(1<<id);
            work(r[L],r[R],val,id-1);
        }
        else work(l[L],l[R],val,id-1);
    }
}
int main()
{
    //freopen("xf.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        maxn=max(maxn,a[i]);
        p1[i][0]=a[i];
        p2[i][0]=a[i];
        add(root[i],root[i-1],a[i],29);
    }
    int gl=log2(n)+2;
    for(int i=1;i<=gl;i++)
    {
        for(int j=1;j<=n;j++)
        {
            p1[j][i]=max(p1[j][i-1],p1[max(1,j-(1<<(i-1)))][i-1]);
            p2[j][i]=max(p2[j][i-1],p2[min(n,j+(1<<(i-1)))][i-1]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        int w=i-1;
        if(i!=1&&p1[w][gl]>a[i])
        {
            for(int j=gl;j>=0;j--)
            {
                if(p1[w][j]<=a[i])
                {
                    w-=(1<<j);
                }
            }
            l1[i]=w;
            if(w!=1&&p1[w-1][gl]>a[i])
            {
                w=w-1;
                for(int j=gl;j>=0;j--)
                {
                    if(p1[w][j]<=a[i])
                    {
                        w-=(1<<j);
                    }
                }
                l2[i]=w;

            }
        }
        w=i+1;
        if(i!=n&&p2[w][gl]>a[i])
        {
            for(int j=gl;j>=0;j--)
            {
                if(p2[w][j]<=a[i])
                {
                    w+=(1<<j);
                }
            }
            r1[i]=min(w,n);
            if(w!=n&&p2[w+1][gl]>a[i])
            {
                w=w+1;
                for(int j=gl;j>=0;j--)
                {
                    if(p2[w][j]<=a[i])
                    {
                        w+=(1<<j);
                        if(w>n)break;
                    }
                }
                r2[i]=min(n,w);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(a[i]==maxn)continue;
        pans=0;
        if(l1[i])
        {
            int ll=0,rr=n;
            if(r1[i])rr=r1[i]-1;
            if(l2[i])ll=l2[i];
            work(root[ll],root[rr],a[i],29);
        }
        ans=max(ans,pans);
        pans=0;
        if(r1[i])
        {
            int ll=0,rr=n;
            if(r2[i])rr=r2[i]-1;
            if(l1[i])ll=l1[i];
            work(root[ll],root[rr],a[i],29);
        }
        ans=max(ans,pans);
    }
    printf("%d\n",ans);
    return 0;
}

  

原文地址:https://www.cnblogs.com/mybing/p/8810378.html

时间: 2024-10-05 04:45:05

bzoj3166: [Heoi2013]Alo 可持久化字典树的相关文章

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密

【BZOJ3166】Alo 可持久化trie树

首先我们枚举次大值,然后确定以这个数为次大值的最大区间. 这个区间就是左边第二个比它大的数的下标+1,右边第二个比它大的数的下标-1. 难就难在找到这个区间. 我们考虑将数排序,然后从大到小将数原来的下标插入set,此时set里的值都大于等于当前插入的数. 所以利用set找到前驱的前驱,后继的后继,就是我们需要的区间. 找到区间后,剩下的就是对于一个给定的数,在一段区间里找到一个数使其异或值最大,直接用可持久化trie就可以了. 1 #include <iostream> 2 #include

BZOJ 3166 HEOI2013 Alo 可持久化Trie树

题目大意:给定一个不重复的序列a,在a中任选一个区间,求区间内的次大值与区间内的任意一个其它数的最大的异或值 首先我们枚举次大值 对于一个次大值 它可能选择的另一个数的取值范围为(l,r) 其中l为这个数左侧第二个比它大的数 r为这个数右侧第二个比它大的数 在这个区间内的Trie树中贪心寻找最大值即可 这个区间怎么求呢?我们维护一棵平衡树 将数从大到小将下标加进平衡树 每加进一个下标 比它大的数的下标都在平衡树中 求两次后继就是r 求两次前驱就是l 我偷懒写了set-- #include<set

【BZOJ2741】【FOTILE模拟赛】L 可持久化字典树+分块

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44496739"); } 题解: 首先我们处理出来sum[0,n]作为异或前缀和,然后答案就不再是[l,r]中间某段区间的异或和,而转化成求了[l?1,r]中任意两点异或和的最大值. 然后我们分块处理出fi,j表示 [第i块的开头,j

hdu 4757 Tree(可持久化字典树)

题目链接:hdu 4757 Tree 题目大意:给定一棵树,每一个节点有一个值.如今有Q次询问,每次询问u到v路径上节点值与w亦或值的最大值. 解题思路:刚開始以为是树链剖分,事实上树链剖分仅仅是用来求LCA(能够不用树链剖分). 可持久化字典树.在每次插入的同一时候,不改动原先的节点.而是对全部改动的节点复制一个新的节点,而且在新的节点 上做操作,这样做的目的是可以获取某次改动前的状态.同过可持久化的操作,保留了改动前后的公共数据. 对给定树上的全部节点权值建立01字典树,然后每一个节点都保存

codechef Xor Queries (可持久化字典树)

题目链接:codechef Xor Queries 题意: 题解: 一棵可持久化字典树就行了. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 using namespace std; 4 5 const int N=5e5+7; 6 struct Node{int son[2],cnt;}ch[N*40]; 7 int root[N],cnt,ed,n; 8 9 void ins(int

Codeforces 706D Vasiliy&#39;s Multiset(可持久化字典树)

[题目链接] http://codeforces.com/problemset/problem/706/D [题目大意] 要求实现一个集合中的三个操作,1:在集合中加入一个元素x,2:从集合中删除一个元素x(保证x存在),3:要求从集合中选出一个数,使得其与给出的数x的异或值最大,输出这个异或值. [题解] 可以将所有的以二进制形式存在01字典树上,删除即插入权值为-1的二进制串,对于异或值最大的操作,我们只要在字典树上按位贪心,从最高位开始尽量保证该位存在最后就能得到答案.写代码的时候直接写了

hdu 6191 Query on A Tree(dfs序+可持久化字典树)

题目链接:hdu 6191 Query on A Tree 题意: 给你一棵树,每个节点有一个值,现在有q个询问,每个询问 询问一个u x,问以u为根的子树中,找一个节点,使得这个节点的值与x异或的值最大,输出那个最大的值. 题解: dfs序和一棵可持久化字典树就搞定了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=a;i<=b;++i) 4

Hdu-4757 Tree(可持久化字典树+lca)

题目链接:点这 我的github地址:点这 Problem Description Zero and One are good friends who always have fun with each other. This time, they decide to do something on a tree which is a kind of graph that there is only one path from node to node. First, Zero will giv