luoguP4098「HEOI2013」ALO

Posted study-ysj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP4098「HEOI2013」ALO相关的知识,希望对你有一定的参考价值。

提供一种更简单码农的做法:

首先做法很明显:固定次小值的位置 \(i\) ,找出次小值的确是这个数的所有区间,那么在可持久化 \(01Trie\) 上找到这些区间的并集就可以按位贪心了

一个结论:若 \(pr\) 为使 \([i,pr]\) 区间中至少有两个数大于 \(a_i\) 的最小位置, \(pl\) 为使 \([pl,i]\) 区间中至少有两个数大于 \(a_i\) 的最大位置,那么 \([pl,pr]\) 区间内的所有数都可以用来和 \(a_i\) 异或更新答案

那么我们先用单调栈扫一遍得到 \(i\) 左右第一个大于 \(a_i\) 的位置 \(ql,qr\) ,之后在 \([1,ql-1]\)\([qr+1,n]\) 内二分,找出最靠近 \(i\) 的且满足 \(max([midl,ql-1]\text or [qr+1,midr])>a_i\) 的位置 \(midl,midr\) 即为所求的 \(pl,pr\)

区间最大值用 \(st\) 表维护,复杂度为 \(O(nlogn)\) ,同时,如果用同样的二分代替第一次的单调栈可以简单地处理第 \(k\) 小的问题

\(code:\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn=5e4+5,D=29;
int n,root[maxn],tot,a[maxn],ans;
//29
struct Trie

    struct nodeint ch[2],siz;t[15000000];
    public:
    void upd(int &rt,int pre,int x,int d)
    
        t[rt=++tot]=t[pre];++t[rt].siz;
        if(d<0)return;
        int k=(x>>d)&1;
        upd(t[rt].ch[k],t[pre].ch[k],x,d-1);
    
    int qry(int rt,int pre,int x,int d)
    
        if(d<0)return 0;
        int k=!((x>>d)&1);
        if(t[t[rt].ch[k]].siz>t[t[pre].ch[k]].siz)return (1<<d)|qry(t[rt].ch[k],t[pre].ch[k],x,d-1);
        return qry(t[rt].ch[k^1],t[pre].ch[k^1],x,d-1);
    
T;
int lh[maxn],rh[maxn];
stack<int>s;
int st[maxn][16],H=15,lg[maxn];
int mx(int l,int r)

    int k=lg[r-l+1];
    return max(st[l][k],st[r-(1<<k)+1][k]);

int main()

    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]),st[i][0]=a[i];
    for(int i=1;i<=n;++i)T.upd(root[i],root[i-1],a[i],D);
    for(int k=1;k<=H;++k)
        for(int i=1;i+(1<<k)-1<=n;++i)
            st[i][k]=max(st[i][k-1],st[i+(1<<(k-1))][k-1]);
    for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
    for(int i=1;i<=n;++i)
    
        while(!s.empty()&&a[i]>a[s.top()])rh[s.top()]=i,s.pop();
        s.push(i);
    
    while(!s.empty())rh[s.top()]=n+1,s.pop();
    for(int i=n;i>=1;--i)
    
        while(!s.empty()&&a[i]>a[s.top()])lh[s.top()]=i,s.pop();
        s.push(i);
    
    while(!s.empty())lh[s.top()]=0,s.pop();
    for(int i=1;i<=n;++i)
    
        int l=rh[i]+1,r=n,mid,anss=n+1;
        while(l<=r)
        
            mid=(l+r)>>1;
            if(mx(rh[i]+1,mid)>a[i])anss=mid,r=mid-1;
            else l=mid+1;
        
        rh[i]=anss;
        l=1,r=lh[i]-1,anss=0;
        while(l<=r)
        
            mid=(l+r)>>1;
            if(mx(mid,lh[i]-1)>a[i])anss=mid,l=mid+1;
            else r=mid-1;
        
        lh[i]=anss;
        ans=max(ans,T.qry(root[rh[i]-1],root[lh[i]],a[i],D));
    
    printf("%d\n",ans);

以上是关于luoguP4098「HEOI2013」ALO的主要内容,如果未能解决你的问题,请参考以下文章

P4098 [HEOI2013]ALO 可持久化01Trie

luoguP4113 [HEOI2012]采花

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树)

[题解] LuoguP4091 [HEOI2016/TJOI2016]求和

李超线段树

BZOJ 3166: [Heoi2013]Alo