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; }