码迷,mamicode.com
首页 > 其他好文 > 详细

P4735 最大异或和

时间:2018-09-21 23:02:18      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:ref   lse   iostream   include   void   name   namespace   targe   个数   

可持久化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;
            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;
}

 

 

P4735 最大异或和

标签:ref   lse   iostream   include   void   name   namespace   targe   个数   

原文地址:https://www.cnblogs.com/kafuuchino/p/9688566.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!