P4735 最大异或和

思路

可持久化Trie树的好题
注意到题目要求求的询问非常的鬼,不太好做
然后有趣的思路就出现了,我们预处理出来异或前缀和s[i],每次询问的x异或上s[n]之后,问题就变成了在l-1~r-1中选一个异或x最大的数
然后因为区间查询,上可持久化Trie树就好了
注意初始的Trie树不能是空树,必须先插入一个节点

代码

洛谷上说这题卡常?不过我一发压着时限跑过去了233

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXlen = 30;
const int MAXN = 300100*2;
int s[MAXN],root[MAXN],Nodecnt=0,n,m;
struct Node{
    int son[2],sz;
}trie[MAXN*30];
void insert(int val,int &o,int d){
    trie[++Nodecnt]=trie[o];
    o=Nodecnt;
    trie[o].sz++;
    if(d>=0)
        insert(val,trie[o].son[(val>>d)&1],d-1);
}
int query(int lroot,int rroot,int val,int d){
    if(d<0)
        return 0;
    int f=(val>>d)&1;
    if(trie[trie[rroot].son[!f]].sz>trie[trie[lroot].son[!f]].sz)
            return (1<<d)+query(trie[lroot].son[!f],trie[rroot].son[!f],val,d-1);
    else
            return query(trie[lroot].son[f],trie[rroot].son[f],val,d-1);
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&s[i]);
    for(int i=1;i<=n;i++)
        s[i]=s[i-1]^s[i];
    insert(s[0],root[0],MAXlen);
    for(int i=1;i<=n;i++){
        root[i]=root[i-1];
        insert(s[i],root[i],MAXlen);
    }
    for(int i=1;i<=m;i++){
        char c=getchar();
        while(c!='A'&&c!='Q')
            c=getchar();
        if(c=='Q'){
            int l,r,x;
            scanf("%d %d %d",&l,&r,&x);
            l--;
            r--;
            x^=s[n];
            int req; 
            if(l==0)
                req=query(0,root[r],x,MAXlen);
            else
                req=query(root[l-1],root[r],x,MAXlen);
            printf("%d
",req);
        }
        else{
            int x;
            scanf("%d",&x);
            n++;
            s[n]=s[n-1]^x;
            root[n]=root[n-1];
            insert(s[n],root[n],MAXlen);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/dreagonm/p/10486705.html