[Heoi2013]Alo

[Heoi2013]Alo

每一个点作为贡献点的区间是包含一个比它大的值,所以我们对于每个点处理四个值

\(L,R,L2,R2\)表示左边第一个比它大的,右边第一个,左边第二个,右边第二个~

这些东西当然可以直接用set处理,但是可以前缀预处理+两边二分替换,甚至是第一遍二分也可以用单调栈代替,能跑得快一些

那么这个点最大的可能贡献的区间就是\([L2+1,R-1]\)\([L+1,R2-1]\)

接下来的问题就是对于一个值\(x\),求区间内的数与它的最大异或,这个我们用可持久化\(trie\)树等奇怪的数据结构实现

#include<cstdio> 
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
 
#define reg register
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
 
char IO;
int rd(){
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;
}
 
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
 
 
const int N=5e4+10;
 
bool be;
 
int n;
int a[N];
int rt[N],nxt[N*32][2];
int m,s[N*32];
 
 
void Pre_Make() {
    rep(i,1,n) {
        int p,pre=rt[i-1];
        p=rt[i]=++m;
        drep(j,29,0) {
            int x=((a[i]>>j)&1);
            nxt[p][x]=++m;
            nxt[p][!x]=nxt[pre][!x];
            p=nxt[p][x],pre=nxt[pre][x];
            s[p]=s[pre]+1;
        }
    }//预处理可持久化trie
}
 
 
int ans;
void Que(int x,int l,int r) {
    l=rt[l-1],r=rt[r];
    int res=0;
    drep(i,29,0) {
        int t=(x&(1<<i))>0;
        if(s[nxt[r][!t]]-s[nxt[l][!t]]>0) res|=1<<i,l=nxt[l][!t],r=nxt[r][!t];
        else l=nxt[l][t],r=nxt[r][t];
    }
    ans=max(ans,res);//贪心查询
}
 
int stk[N],top;
int L[N],R[N],LL[N],RR[N]; // LL=L2,RR=R2
 
struct Node{
    int x,id,t;
    bool operator < (const Node __) const {
        return id<__.id;
    }
}B[N];
int cmp(const Node x,const Node y){
    return x.id>y.id;
}
int cnt;
 
bool ed;
 
int main(){
    n=rd();
    rep(i,1,n) a[i]=rd();
    Pre_Make();
    rep(i,1,n) {
        while(top && a[stk[top]]<a[i]) top--;
        L[i]=stk[top];
        if(L[i]>1) B[++cnt]=(Node){a[i],L[i]-1,i};
        stk[++top]=i;
    }
    top=0;
    sort(B+1,B+cnt+1);
    int p=1;//一遍单调栈+一遍二分预处理
    rep(i,1,n) {
        while(top && a[stk[top]]<a[i]) top--;
        stk[++top]=i;
        while(p<=cnt && B[p].id<=i) {
            int l=1,r=top,res=0;
            while(l<=r) {
                int mid=(l+r)>>1;
                if(a[stk[mid]]>B[p].x) l=mid+1,res=stk[mid];
                else r=mid-1;
                LL[B[p].t]=res;
            }
            p++;
        }
    }
    top=cnt=0;
    drep(i,n,1) {
        while(top && a[stk[top]]<a[i]) top--;
        R[i]=stk[top];
        if(R[i]<n && R[i]) B[++cnt]=(Node){a[i],R[i]+1,i};
        stk[++top]=i;
    }
    sort(B+1,B+cnt+1,cmp);
    p=1;
    top=0;
    drep(i,n,1) {
        while(top && a[stk[top]]<a[i]) top--;
        stk[++top]=i;
        while(p<=cnt && B[p].id>=i) {
            int l=1,r=top,res=0;
            while(l<=r) {
                int mid=(l+r)>>1;
                if(a[stk[mid]]>B[p].x) l=mid+1,res=stk[mid];
                else r=mid-1;
                RR[B[p].t]=res;
            }
            p++;
        }
    }
    rep(i,1,n) {
        if(!L[i] && !R[i]) continue;
        Que(a[i],LL[i]+1,RR[i]?RR[i]-1:n);
    }
    printf("%d\n",ans);
}
 
 
posted @ 2019-11-08 16:18  chasedeath  阅读(136)  评论(0编辑  收藏  举报