可持久化Trie树

可持久化数据结构汇总

如果会了主席树之类的东西,这应该就很好理解了吧

可持久Trie主要处理的就是xor相关的问题

把维护的数转成2进制存入trie,查询的时候就从高位向低贪心,尽可能的在trie中选择表示询问值取反的儿子 ,这样才能使异或和最大

代码注释中...

例题1:P4735 最大异或和

版题啦,trie维护xor前缀和,题解去看洛谷的吧我懒的写了

//死活70分A不了
//(不过我觉得应该没什么大问题)
//本题洛谷卡常,建议吸氧+快读 
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

long long read(){
    long long ans=0,fh=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return ans*fh;
}

struct LastTrie{//二进制存储 
    struct tr{
        int ch[2],sum;
    }tr[42000005];
    int root[300005],size,pn;
    int create(int val){
        pn++;tr[pn].sum=val;
        tr[pn].ch[0]=tr[pn].ch[1]=0;
        return pn;
    }
    int build(int step){
        int x=create(0);
        if(step==0) return 0;
        tr[x].ch[0]=build(step-1);
        tr[x].ch[1]=build(step-1);
        return x;
    }
    int insert(int step,int pre,int num,int val){
        int x=create(tr[pre].sum+val);
        if(step==0) return x;
        tr[x].ch[0]=tr[pre].ch[0];
        tr[x].ch[1]=tr[pre].ch[1];
        bool c=(num>>(step-1))&1;
        tr[x].ch[c]=insert(step-1,tr[pre].ch[c],num,val);
        return x;
    }
    void Init(int mys){
        size=mys;pn=0;
        root[0]=build(size);
    }
    void Insert(int id,int pre,int num,int val){
        root[id]=insert(size,root[pre],num,val);
    }
    int Query(int l,int r,int num){
        int pre=root[l-1],x=root[r];
        int ans=0;
        for(int i=size;i>=1;i--){//从高位到低位贪心 
            int c=(num>>(i-1))&1;
            if(tr[tr[x].ch[!c]].sum-tr[tr[pre].ch[!c]].sum>0){//判断!c这一位在l-r中是否存在 
                x=tr[x].ch[!c],pre=tr[pre].ch[!c];
                ans+=(1<<(i-1));
            }else x=tr[x].ch[c],pre=tr[pre].ch[c];
        }
        return ans;
    }
}ltr;

int n,qn;
int arr[300005],b[300005];

int main(){
    ltr.Init(24);
    cin>>n>>qn;
    b[0]=0;
    for(int i=1;i<=n;i++){
        arr[i]=read();
        b[i]=b[i-1]^arr[i];
        ltr.Insert(i,i-1,b[i],1);
    }
    for(int i=1;i<=qn;i++){
        char type;
        int l,r,val;
        for(;;){type=getchar();if(type=='A'||type=='Q') break;}
        switch(type){
            case 'A':{
                arr[++n]=read();
                b[n]=b[n-1]^arr[n];
                ltr.Insert(n,n-1,b[n],1);
                break;
            }case 'Q':{
                l=read();r=read();val=read();
                printf("%d\n",ltr.Query(l-1,r-1,val^b[n]));
                break;
            }
        }
    }
    return 0;
}
View Code

例题2:HDU4757 Tree

 从序列变到了树上...用差分思想解决,trie维护的是当前点到根节点路径上的信息。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

struct LastTrie{//二进制存储 
    struct tr{
        int ch[2],sum;
    }tr[4000000];
    int root[200005],size,pn;
    int create(int val){
        pn++;tr[pn].sum=val;
        tr[pn].ch[0]=tr[pn].ch[1]=0;
        return pn;
    }
    int build(int step){
        int x=create(0);
        if(step==0) return 0;
        tr[x].ch[0]=build(step-1);
        tr[x].ch[1]=build(step-1);
        return x;
    }
    int insert(int step,int pre,int num,int val){
        int x=create(tr[pre].sum+val);
        if(step==0) return x;
        tr[x].ch[0]=tr[pre].ch[0];
        tr[x].ch[1]=tr[pre].ch[1];
        bool c=(num>>(step-1))&1;
        tr[x].ch[c]=insert(step-1,tr[pre].ch[c],num,val);
        return x;
    }
    void Init(int mys){
        size=mys;pn=0;
        root[0]=build(size);
    }
    void Insert(int id,int pre,int num,int val){
        root[id]=insert(size,root[pre],num,val);
    }
    int Query(int x,int y,int lca,int num){
        x=root[x];y=root[y];lca=root[lca];
        int ans=0;
        for(int i=size;i>=1;i--){
            int c=(num>>(i-1))&1;
            if(tr[tr[x].ch[!c]].sum+tr[tr[y].ch[!c]].sum-2*tr[tr[lca].ch[!c]].sum>0){//判断!c是否存在 
                x=tr[x].ch[!c],y=tr[y].ch[!c],lca=tr[lca].ch[!c];
                ans+=(1<<(i-1));
            }else x=tr[x].ch[c],y=tr[y].ch[c],lca=tr[lca].ch[c];
        }
        return ans;
    }
}ltr;
//lca相关 
int root,en,n,qn,logn;
int to[200005],last[200005],nxt[200005];
int prt[200005],dep[200005],jmp[200005][25];
void addedge(int u,int v){
    en++;to[en]=v;
    nxt[en]=last[u];
    last[u]=en;
}
void trdfs(int x,int fa,int d){
    prt[x]=fa;dep[x]=d;
    for(int i=last[x];i!=0;i=nxt[i]){
        int go=to[i];
        if(go!=fa) trdfs(go,x,d+1);
    }
}
void lcainit(){
    for(int i=1;i<=n;i++) jmp[i][0]=prt[i];
    for(int j=1;j<=logn;j++)
        for(int i=1;i<=n;i++)
            jmp[i][j]=jmp[jmp[i][j-1]][j-1];
}
int getlca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    if(dep[x]!=dep[y]){
        for(int i=logn;i>=0;i--){
            int up=jmp[x][i];
            if(dep[up]>dep[y]) x=up;
        }x=prt[x];
    }
    if(x==y) return x;
    for(int i=logn;i>=0;i--){
        int upx=jmp[x][i],upy=jmp[y][i];
        if(upx!=upy) x=upx,y=upy;
    }
    return prt[x];
}
int ptv[200005];
void indfs(int x){
    ltr.Insert(x,prt[x],ptv[x],1);
    for(int i=last[x];i!=0;i=nxt[i])
        if(to[i]!=prt[x]) indfs(to[i]);
}
void Allclear(){
    for(int i=0;i<200005;i++){
        for(int j=0;j<25;j++) jmp[i][j]=0;
        to[i]=last[i]=nxt[i]=prt[i]=dep[i]=ptv[i]=0;
    }
}
int main(){
    while(cin>>n>>qn){
        Allclear();ltr.Init(16);
        root=1;logn=log2(n);
        for(int i=1;i<=n;i++)
            scanf("%d",&ptv[i]);
        for(int i=1;i<=n-1;i++){
              int u,v;scanf("%d%d",&u,&v);
            addedge(u,v);addedge(v,u);
        }
        trdfs(root,0,1);
        lcainit();
        indfs(root);
        for(int i=1;i<=qn;i++){
            int x,y,lca,val;
            scanf("%d%d%d",&x,&y,&val);
            lca=getlca(x,y);
            int ans=ltr.Query(x,y,lca,val);
            printf("%d\n",max(ans,ptv[lca]^val));
        }
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/sun123zxy/p/lastingtrie.html