[bzoj4260]Codechef REBXOR【trie树】

【题目链接】
  http://www.lydsy.com/JudgeOnline/problem.php?id=4260
【题解】
  一段的异或和可以转换为两个前缀的异或。
  因此可以用trie树预处理出任意一个节点向左或向右的最大异或。
  然后求出前缀/后缀最大值,枚举断点即可。

/* --------------
    user Vanisher
    problem bzoj-4260 
----------------*/
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    K       29
# define    N       400010
using namespace std;
int read(){
    int tmp=0, fh=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    return tmp*fh;
}
struct node{
    int son[2];
}T[N*31];
int ml[N],mr[N],s[N],place,n,a[N],ans;
void extend(int x){
    int p=0,j;
    for (int i=K; i>=0; i--){
        if ((x&(1<<i))==0)
            j=0; else j=1;
        if (T[p].son[j]==0){
            T[p].son[j]=++place;
            p=T[p].son[j];
        }
        else p=T[p].son[j];
    }
}
int query(int x){
    int p=0, num=0, j;
    for (int i=K; i>=0; i--){
        if ((x&(1<<i))==0)
            j=0; else j=1;
        if (T[p].son[j^1]!=0){
            num=num+(1<<i);
            p=T[p].son[j^1];
        }
        else p=T[p].son[j];
    }
    return num;
}
int main(){
    n=read();
    for (int i=1; i<=n; i++)
        a[i]=read();
    for (int i=1; i<=n; i++)
        s[i]=s[i-1]^a[i];
    for (int i=1; i<=n; i++){
        extend(s[i-1]);
        ml[i]=max(query(s[i]),ml[i-1]);
    } 
    memset(T,0,sizeof(T)); place=0;
    for (int i=n; i>=1; i--)
        s[i]=s[i+1]^a[i];
    for (int i=n; i>=1; i--){
        extend(s[i+1]);
        mr[i]=max(query(s[i]),mr[i+1]);
    }
    for (int i=1; i<n; i++)
        ans=max(ans,ml[i]+mr[i+1]);
    printf("%d\n",ans);
    return 0;
}
posted @ 2018-03-16 19:09  Vanisher  阅读(100)  评论(0编辑  收藏  举报