bzoj3261 最大异或和 可持久化trie

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36056315/article/details/81153609

链接

https://www.lydsy.com/JudgeOnline/problem.php?id=3261

做法

我们先考虑没有修改操作,只有询问的话怎么做,我们记sum[i]表示i的后缀异或和,那么我们每个询问相当于查询区间对一个数x异或后的最大值,那么贪心很明显,位数从高到低,如果有数这个位置上可以和x异或起来是1,那么我肯定不会去选和x异或起来这位上是0的。根据这个性质,我们考虑trie树,如果当前节点的子节点有能和x异或起来为1的节点,就走下去,不然只能走另一边了,那么区间的话我们就可持久化一下,这个具体就和主席树是一模一样的了,这里不多赘述了。
接下来我们要考虑修改的问题,我们另sum[i]表示i的前缀异或和,注意这里和上面不同了,变成了前缀,那么我们每个点到n的异或和就可以表示为sum[i-1]^sum[n]了对吧,接下来的步骤就和上面是一样的了。

代码

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#define LL long long
#define N (600005)
using namespace std;
int n,m,x,l,r,now,ans,cnt;
int sum[N],root[N],size[20000005],son[20000005][2];
char c[10];
template <typename T> void read(T&t) {
    t=0;
    bool fl=true;
    char p=getchar();
    while (!isdigit(p)) {
        if (p=='-') fl=false;
        p=getchar();
    }
    do {
        (t*=10)+=p-48;p=getchar();
    }while (isdigit(p));
    if (!fl) t=-t;
}
void insert(int &u,int pre,int data,int ws){
    u=++cnt;
    size[u]=size[pre]+1;
    //printf("%d %d %d\n",data,ws,size[u]);
    if (ws==1) return;
    son[u][0]=son[pre][0];
    son[u][1]=son[pre][1];
    if (data&(1<<ws-2)) insert(son[u][1],son[pre][1],data,ws-1);
    else insert(son[u][0],son[pre][0],data,ws-1);
}
void query(int l,int r,int ws){
    //printf("%d %d\n",ws,ans);
    if (ws==1) return;
    int cc=(now&(1<<ws-2));
    if (cc) cc=0;
    else cc=1;
    //printf("ws %d %d\n",ws,cc);
    if (size[son[r][cc]]-size[son[l][cc]]) ans+=(1<<(ws-2)),query(son[l][cc],son[r][cc],ws-1);
    else query(son[l][cc^1],son[r][cc^1],ws-1);
}
int main(){
    read(n),read(m);
    insert(root[0],0,0,31);
    for (int i=1;i<=n;i++){
        read(x);
        sum[i]=sum[i-1]^x;
        insert(root[i],root[i-1],sum[i],31);
    }
    while (m--){
        scanf("%s",c);
        if (c[0]=='A'){
            read(x);
            n++;
            sum[n]=sum[n-1]^x;
            insert(root[n],root[n-1],sum[n],31);
        }
        if (c[0]=='Q'){
            read(l),read(r),read(x);
            now=sum[n]^x;
            //printf("now %d\n",now);
            ans=0;
            int tt;
            if (l==1) tt=0;
            else tt=root[l-2];
            query(tt,root[r-1],31);
            printf("%d\n",ans);
        }
    }


    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36056315/article/details/81153609