P4735 最大异或和

可持久化Trie
 
据n^n=0,我们可以把问题转化为前缀异或和(设为s[i]),也就是求 s[n]^s[p] 的最大值
 
显然,这是经典的Trie上贪心问题。但是询问次数过多,我们总不能每次都建一棵完整的树。
注意到,对于每次询问我们所需的Trie都只有很小的不同。
于是我们就可以用可持久化Trie,原理类似主席树。
 
(不开O2只有90pts......)
 
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,cnt,ch[16800002][2],sum[16800002],rt[600002],s[600002];
inline void update(int o,int pre,int d,int x){ //插入操作:我们仅新建一条链,其他部分与老版本共用
    if(d<0) return ;
    int to=(x>>d)&1;
    ch[o][!to]=ch[pre][!to];  //接到老版本上
    sum[ch[o][to]=++cnt]=sum[ch[pre][to]]+1; //统计个数
    update(ch[o][to],ch[pre][to],d-1,x); 
}
inline int query(int o,int pre,int d,int x){ //查询操作,与主席树相似
    if(d<0) return 0;
    int to=(x>>d)&1;
    if(sum[ch[o][!to]]>sum[ch[pre][!to]]) return (1<<d)+query(ch[o][!to],ch[pre][!to],d-1,x);  //在区间内可以走
    else return query(ch[o][to],ch[pre][to],d-1,x);
}
int main(){
    scanf("%d%d",&n,&m); int q1,q2,q3; char opt[3];
    update(rt[0]=++cnt,0,25,0); //预建一棵全0树
    for(int i=1;i<=n;++i) scanf("%d",&q1),s[i]=s[i-1]^q1,update(rt[i]=++cnt,rt[i-1],25,s[i]); 
    for(int i=1;i<=m;++i){
        scanf("%s",opt); scanf("%d",&q1);
        if(opt[0]=='A') ++n,s[n]=s[n-1]^q1,update(rt[n]=++cnt,rt[n-1],25,s[n]);
        else{
            scanf("%d%d",&q2,&q3);
            --q1; --q2; //emmm.....我也不知道为啥要减,知道的请@我qwq
            if(q1==0) printf("%d\n",query(rt[q2],0,25,q3^s[n]));
            else printf("%d\n",query(rt[q2],rt[q1-1],25,q3^s[n]));
        }
    }return 0;
}

 

 
posted @ 2018-09-21 21:36  kafuuchino  阅读(173)  评论(0编辑  收藏  举报