BZOJ 4260: Codechef REBXOR 字典树

题目

字典树可以用来找集合中两个数的异或值的最大值

本题题意可以转换为求

max(l[i]+r[i+1])
///l[i]=a[l]^a[l+1]^...^a[r] 1<=l<=r<=i
///r[i]=a[l]^a[l+1]^...^a[r] i<=l<=r<=N

再设一个前缀异或和 利用异或的定义求出l[i] 后缀同理

x[i]=a[0]^a[1]^...^a[i]///a[0]=0
l[i]=max(x[i]^x[j])///0<=j<i

书上的AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=4e5+5;
const int Z=2;
 
int n,tot=1;
int ch[N<<5][Z],l[N],r[N],A[N];
 
void init()
{
    memset(ch,0,sizeof(ch));
}
///将当前的前/后缀异或和化为31位2进制串,加入Trie树
bool Insert(int x)
{
    int u=1;
    for(int i=1<<30;i;i>>=1)
    {
        int c=(x&i)?1:0;
        if(!ch[u][c])ch[u][c]=++tot;
        u=ch[u][c];
    }
}
 
int Find(int x)
{
    int u=1,ans=0;
    for(int i=1<<30;i;i>>=1)
    {
        int c=(x&i)?0:1;
 
        if(ch[u][c])
        {
            ans+=i;
            u=ch[u][c];
        }
        else u=ch[u][!c];
    }
    return ans;
}
int main()
{
    int now,ans=0;
    scanf("%d",&n);
    Insert(now=0);
 
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&A[i]);
        now^=A[i];
        Insert(now);
        l[i]=max(l[i-1],Find(now));
    }
    init();
    tot=1;
    Insert(now=0);
    for(int i=n;i>=1;i--)
    {
        now^=A[i];
        Insert(now);
        r[i]=max(r[i+1],Find(now));
    }
    for(int i=1;i<n;i++)
        ans=max(ans,l[i]+r[i+1]);
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yyyccww/article/details/81185161