BZOJ-3261: 最大异或和

[文章目录]

Description

给定一个非负整数序列 {a},初始长度为 N。
有M个操作,有以下两种操作类型:
1 、A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1。
2 、Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少。

如果维护一个后缀的亦或和的话,发现这个东西随时在变,考虑转化成前缀的亦或和。后缀=前缀^S(S为这个序列的亦或和) => 找一个前缀亦或和,使得前缀^S^x最大。
用trie树维护所有的前缀的亦或和每一位上的值,将其可持久化,每个位置的trie是由上一个位置trie得来,然后在查询的时候进入r-1的trie树,判断当前节点的最近时间戳是否大于等于l-1,进行贪心。注意初始化空节点的时间戳和前缀没有元素的情况。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,tot,sum,rot[601000];
struct Trie
{
    int c[2],id;
}t[20000000];
void insert(int id,int y,int z)
{
    int p=++tot; rot[id]=tot; bool fl;
    for(int i=24;~i;--i)
    {
        fl=(z>>i)&1;
        t[p].c[fl^1]=t[y].c[fl^1];
        t[p].c[fl]=++tot; t[tot].id=id;
        p=t[p].c[fl]; y=t[y].c[fl];
    }
}
int query(int x,int y,int z)
{
    int re=0; bool fl;
    for(int i=24;~i;--i)
    {
        fl=((z>>i)&1)^1;
        if(t[t[x].c[fl]].id>=y) re|=(1<<i);
        else fl^=1;
        x=t[x].c[fl];
    }
    return re;
}
int main()
{
    scanf("%d%d",&n,&m);
    int x; t[0].id=-1;
    insert(0,0,0);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&x); sum^=x;
        insert(i,rot[i-1],sum);
    }
    char sw[10]; int l,r;
    while(m--)
    {
        scanf("%s",sw);
        if(sw[0]=='A')
        {
            scanf("%d",&x); sum^=x;
            ++n; insert(n,rot[n-1],sum);
        }
        else
        {
            scanf("%d%d%d",&l,&r,&x);
            printf("%d\n",query(rot[r-1],l-1,x^sum));
        }
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注