P4735 最大异或和 /【模板】可持久化Trie

本题是可持久化0-1 trie树的题目

做这题我相信都已经学会可持久化trie树的基本方法,所以本文不过多解释原理

在下面代码中有很多注释,介绍了写法。

可持久化trie树的重点就是他只在原有基础上新增了添加的内容,而保留前面的,所以用到了很多复制的操作

01trie树当中,假如该位置为1,那么我们只需要把0引用到前一版本的0上面,这样就复制过来了,而前一版本的1还没有复制

所以我们可以采取递归的方法不断复制下去。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<map>
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));
            
        }
        
    }
}
View Code

 

posted @ 2020-02-02 19:32  朝暮不思  阅读(171)  评论(0编辑  收藏  举报