bzoj2134: 单选错位(trie)

  预处理前后缀异或和,用trie得到前后缀最大答案,枚举中间点把左右两边加起来就是当前中间点的最大答案了...这个操作没见过,比较有意思,记录一下

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=500010, inf=1e9;
struct poi{int nxt[2];}tree[maxn*30];
int n, ans, tott;
int a[maxn], suml[maxn], sumr[maxn], ansl[maxn], ansr[maxn];
inline void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<'0' || c>'9') c=='-'&&(f=-1), c=getchar();
    while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
    k*=f;    
} 
inline int getans(int x)
{
    int ans=0, now=0;
    for(int i=30, y;~i;i--)
    if(tree[now].nxt[(y=(x&(1<<i))!=0)^1])
    ans+=(1<<i), now=tree[now].nxt[y^1];
    else now=tree[now].nxt[y];
    return ans;
}
inline void insert(int x)
{
    int now=0;
    for(int i=30, y;~i;i--)
    if(tree[now].nxt[y=(x&(1<<i))!=0]) now=tree[now].nxt[y];
    else tree[now].nxt[y]=++tott, now=tott;
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++) read(a[i]), suml[i]=suml[i-1]^a[i];
    for(int i=n;i;i--) sumr[i]=sumr[i+1]^a[i];
    insert(0);
    for(int i=1;i<=n;i++) ansl[i]=max(ansl[i-1], getans(suml[i])), insert(suml[i]);
    memset(tree, 0, sizeof(tree)); insert(0);
    for(int i=n;i;i--) ansr[i]=max(ansr[i+1], getans(sumr[i])), insert(sumr[i]);
    for(int i=1;i<=n;i++) ans=max(ans, ansl[i]+ansr[i]);
    printf("%d\n", ans);
}
View Code

 

posted @ 2018-02-08 17:15  Sakits  阅读(135)  评论(0编辑  收藏