BZOJ 3261 最大异或和

题解:

答案 x^s[n]^s[p-1]

s是前缀异或

可持久化Trie树

按照二进制把数加进去

覆盖的路径权值+1

然后贪心找

用权值的差判断有没有这一位

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int u=31;
const int maxn=600009;

int n,m;
int s[maxn]={0};

int nn=0;
int root[maxn]={0};
int ch[maxn*31][2]={0},d[maxn*31]={0};
void Inser(int &now,int pre,int bi,int x){
    now=++nn;
    ch[now][0]=ch[pre][0];
    ch[now][1]=ch[pre][1];
    d[now]=d[pre]+1;
    if(bi==1)return;
    if(x&(1<<(bi-2)))Inser(ch[now][1],ch[pre][1],bi-1,x);
    else Inser(ch[now][0],ch[pre][0],bi-1,x);
}
int Querymax(int now,int pre,int bi,int x){
    if(bi==1)return 0;
    if(x&(1<<(bi-2))){
        if(d[ch[now][0]]-d[ch[pre][0]]==0){
            return Querymax(ch[now][1],ch[pre][1],bi-1,x);
        }else{
            return (1<<(bi-2))+Querymax(ch[now][0],ch[pre][0],bi-1,x);
        }
    }else{
        if(d[ch[now][1]]-d[ch[pre][1]]==0){
            return Querymax(ch[now][0],ch[pre][0],bi-1,x);
        }else{
            return (1<<(bi-2))+Querymax(ch[now][1],ch[pre][1],bi-1,x);
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    
    root[0]=++nn;
    for(int i=1;i<=n;++i){
        int x;scanf("%d",&x);
        s[i]=s[i-1]^x;
        Inser(root[i],root[i-1],u,s[i]);
    }
    
    
    while(m--){
        char opty=getchar();
        while((opty!='A')&&(opty!='Q'))opty=getchar();
        int x,y,z;
        if(opty=='A'){
            scanf("%d",&x);
            ++n;s[n]=s[n-1]^x;
            Inser(root[n],root[n-1],u,s[n]);
        }else{
            scanf("%d%d%d",&x,&y,&z);
            if(x==1){
                int tm=z^s[n];
                printf("%d\n",max(tm,Querymax(root[y-1],root[0],u,z^s[n])));
            }else{
                printf("%d\n",Querymax(root[y-1],root[x-2],u,z^s[n]));
            }
        }
    }
    return 0;
}

 

posted @ 2018-03-20 15:53  ws_zzy  阅读(146)  评论(0编辑  收藏  举报