可持久化Trie樹
阿新 • • 發佈:2019-01-01
如果會了主席樹之類的東西,這應該就很好理解了吧
可持久Trie主要處理的就是xor相關的問題
把維護的數轉成2進位制存入trie,查詢的時候就從高位向低貪心,儘可能的在trie中選擇表示詢問值取反的兒子 ,這樣才能使異或和最大
程式碼註釋中...
例題1:P4735 最大異或和
版題啦,trie維護xor字首和,題解去看洛谷的吧我懶的寫了
//死活70分A不了 //(不過我覺得應該沒什麼大問題) //本題洛谷卡常,建議吸氧+快讀 #include<iostream> #include<cstdio> #includeView Code<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; }
例題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