[BZOJ3261]最大异或和(可持久化trie树)

题目描述

传送门

题解

sum[i] 表示 1...i 的异或和,那么题目要求的即为 sum[i] ^ sum[n] ^ x 。由于 sum[n] x 都是定值,那么我们需要维护的就是 sum[i]
sum[i] 转化为二进制数,然后建立可持久化trie树。利用前缀和相减的思想,对于每一个询问只需要根据 sum[n] ^ x 的每一个二进制位在trie树上对应寻找就可以了,尽量让异或值为1,实在不行就为0。
需要注意的一点是,答案可能为 sum[n] ^ x ,即 1 n 的异或值,需要特殊处理。

代码

#include
#include
#include
using namespace std;
#define N 600005
#define sz 25

int n,m,x,tot,cnt,size,l,r,ans;
int root[N];
int sum[N*30],ch[N*30][2];
int dig[30];

int read()
{
    int x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
void write(int x)
{
    if (!x) {puts("0");return;}
    dig[0]=0;
    while (x)
    {
        dig[++dig[0]]=x%10;
        x/=10;
    }
    for (int i=dig[0];i>=1;--i) putchar('0'+dig[i]);
    putchar('\n');
}
void insert(int &now,int x,int dep)
{
    sum[++size]=sum[now]+1,ch[size][0]=ch[now][0],ch[size][1]=ch[now][1];now=size;
    if (dep==-1) return;
    int k=(x>>dep)&1;
    if (!k) insert(ch[now][0],x,dep-1);
    else insert(ch[now][1],x,dep-1);
}
void query(int l,int r,int x,int dep)
{
    if (dep==-1) return;
    int k=(x>>dep)&1;
    if (sum[ch[r][k^1]]-sum[ch[l][k^1]]>0)
    {
        ans|=1<1],ch[r][k^1],x,dep-1);
    }
    else
        query(ch[l][k],ch[r][k],x,dep-1);
}
int main()
{
    n=read();m=read();
    for (int i=1;i<=n;++i)
    {
        x=read();
        tot^=x;root[i]=root[i-1];
        insert(root[i],tot,sz-1);
    }
    cnt=n;
    for (int i=1;i<=m;++i)
    {
        char opt=getchar();
        while (opt!='A'&&opt!='Q') opt=getchar();
        if (opt=='A')
        {
            x=read();
            tot^=x;++cnt;root[cnt]=root[cnt-1];
            insert(root[cnt],tot,sz-1);
        }
        else
        {
            l=read();r=read();x=read();ans=0;
            --l,--r;l=max(l,0);r=max(r,0);
            query(root[l-1],root[r],tot^x,sz-1);
            if (l==0) ans=max(ans,tot^x);
            write(ans);
        }
    }
}

总结

①牵扯到xor的东西要有意识地想到用trie树。

你可能感兴趣的:(题解,可持久化,trie)