本题是可持久化0-1 trie树的题目
做这题我相信都已经学会可持久化trie树的基本方法,所以本文不过多解释原理
在下面代码中有很多注释,介绍了写法。
可持久化trie树的重点就是他只在原有基础上新增了添加的内容,而保留前面的,所以用到了很多复制的操作
01trie树当中,假如该位置为1,那么我们只需要把0引用到前一版本的0上面,这样就复制过来了,而前一版本的1还没有复制
所以我们可以采取递归的方法不断复制下去。
#include #include #include #include #include #include #include using namespace std; typedef long long ll; const int N=600010; const int M=N*25; int tr[M][2]; int idx; int s[N]; int root[N]; int id[M]; void insert(int u,int k,int p,int q){ if(k<0){ //23次操作全部结束后更新该位置的编号 id[q]=u; return ; } int v=s[u]>>k&1; if(p){ //如果该节点存在子孩子,那么就把v^1的值引用他 tr[q][v^1]=tr[p][v^1]; //把前一次的复制一遍 } tr[q][v]=++idx; //给现在的值开辟新节点 insert(u,k-1,tr[p][v],tr[q][v]);//因为我们开辟了新节点,所以上次的有一段节点没保存,因此需要将他传递保存 id[q]=max(id[tr[q][0]],id[tr[q][1]]); //更新完毕后将左右节点的编号最大值存储,编号的意思是第几个前缀和 } int query(int u,int c,int l){ //u是最后一次持久化结构的root节点,c是我们要询问的值,l是边界 int i; int res=0; for(i=23;i>=0;i--){ int v=c>>i&1; if(id[tr[u][v^1]]>=l){ //只有节点编号满足条件才能转移 res+=1<<i; u=tr[u][v^1]; } else u=tr[u][v]; } return res; } int main(){ int i; int n,m; scanf("%d%d",&n,&m); root[0]=++idx; id[0]=-1; s[0]=0; insert(0,23,0,root[0]); for(i=1;i<=n;i++){ scanf("%d",&s[i]); s[i]^=s[i-1]; root[i]=++idx; insert(i,23,root[i-1],root[i]); } char t[2]; for(i=1;i<=m;i++){ scanf("%s",t); if(*t=='A'){ n++; scanf("%d",&s[n]); s[n]^=s[n-1]; root[n]=++idx; insert(n,23,root[n-1],root[n]); } else{ int l,r,x; scanf("%d%d%d",&l,&r,&x); printf("%d\n",query(root[r-1],s[n]^x,l-1)); } } }