1. 程式人生 > >可持久化Trie樹

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