可持久化Trie树
Posted sun123zxy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可持久化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 ",ltr.Query(l-1,r-1,val^b[n])); break; } } } return 0; }
例题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 ",max(ans,ptv[lca]^val)); } } return 0; }
以上是关于可持久化Trie树的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ5338 [TJOI2018] Xor 可持久化Trie树dfs序
luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树
luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树