xsy1214 异或路径(xorpath) 点分治+可持久化trie
Posted xiefengze1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了xsy1214 异或路径(xorpath) 点分治+可持久化trie相关的知识,希望对你有一定的参考价值。
题目大意:给你一棵$n$个点的树,每个点有一个点权$x$,问你所有路径中点权异或和最大的路径的异或和
数据范围:$n≤30000$,$x≤2^{31}-1$。
如果是边上有点权的话非常简单,直接一个$trie$就可以水过去了。
然而这题是点权,非常烦人。我们考虑用点分治去解决。
假设当前需要遍历的树的重心是$x$,我们开一个可持久化$trie$,我们用$son[x][i]$表示$x$的第$i$个儿子(我们假设总共有$p_x$个),将从$son[x][i]$出发的路径异或和加入第$[i,p_x]$个$trie$树中,当我们遍历出一条从$x$出发,经过$son[x][i]$的路径时,我们把这个路径的异或和放入第$i-1$个$trie$树中进行搜索。
我们已知点分治的时间复杂度是$O(n log n)$,由于这里面套了一个可持久化$trie$,那么时间复杂度就是$O(n log n log_2^{max{x}}$。
然后我的$trie$树出了锅,路径长度的最后一个二进制位没有被塞进$trie$中,然后成功$GG$
1 #include<bits/stdc++.h> 2 #define M 100005 3 #define INF 19260817 4 using namespace std; 5 6 struct edge{int u,next;}e[M*2]={0}; int head[M]={0},Use=0; 7 void add(int x,int y){Use++;e[Use].u=y;e[Use].next=head[x];head[x]=Use;} 8 9 int num[M]={0},vis[M]={0}; 10 11 int siz[M]={0}; 12 13 void dfssiz(int x,int fa){ 14 siz[x]=1; 15 for(int i=head[x];i;i=e[i].next) 16 if(e[i].u!=fa&&vis[e[i].u]==0){ 17 dfssiz(e[i].u,x); 18 siz[x]+=siz[e[i].u]; 19 } 20 } 21 int minn,minid; 22 void dfsmax(int x,int fa,int fasiz){ 23 int maxn=fasiz-siz[x]; 24 for(int i=head[x];i;i=e[i].next) 25 if(e[i].u!=fa&&vis[e[i].u]==0){ 26 dfsmax(e[i].u,x,fasiz); 27 maxn=max(maxn,siz[e[i].u]); 28 } 29 if(maxn<minn) minn=maxn,minid=x; 30 } 31 32 int makeroot(int x){ 33 dfssiz(x,0); 34 minn=INF; minid=0; 35 dfsmax(x,0,siz[x]); 36 return minid; 37 } 38 39 struct trie{ 40 int a[2]; 41 }a[M*20]={0};int root[M]={0},use=0; 42 43 void add(int &x,int zhi,int wei){ 44 a[++use]=a[x]; x=use; int hh=0; 45 if(wei<0) return; 46 if((1<<wei)&zhi) hh=1; 47 add(a[x].a[hh],zhi,wei-1); 48 } 49 int query(int x,int zhi,int wei){ 50 if(wei<0||x==0) return 0; 51 int hh=1,ans=0; 52 if((1<<wei)&zhi) hh=0; 53 if(!a[x].a[hh]) return query(a[x].a[hh^1],zhi,wei-1); 54 else return (1<<wei)+query(a[x].a[hh],zhi,wei-1); 55 } 56 57 void dfsdis(int x,int fa,int hh,int cnt){ 58 hh^=num[x]; 59 add(root[cnt],hh,30); 60 for(int i=head[x];i;i=e[i].next) 61 if(e[i].u!=fa&&vis[e[i].u]==0){ 62 dfsdis(e[i].u,x,hh,cnt); 63 } 64 } 65 66 int ans=0; 67 68 void query(int x,int fa,int hh,int cnt){ 69 hh^=num[x]; 70 int now=query(root[cnt-1],hh,30); 71 ans=max(ans,now); 72 ans=max(ans,hh); 73 for(int i=head[x];i;i=e[i].next) 74 if(e[i].u!=fa&&vis[e[i].u]==0){ 75 query(e[i].u,x,hh,cnt); 76 } 77 } 78 79 void calc(int x){ 80 int cnt=0; 81 for(int i=head[x];i;i=e[i].next) 82 if(vis[e[i].u]==0){ 83 cnt++; root[cnt]=root[cnt-1]; 84 dfsdis(e[i].u,x,0,cnt); 85 } 86 cnt=0; 87 for(int i=head[x];i;i=e[i].next) 88 if(vis[e[i].u]==0){ 89 cnt++; 90 ans=max(ans,num[x]); 91 query(e[i].u,x,num[x],cnt); 92 } 93 use=0; memset(root,0,(cnt+1)<<2); 94 } 95 96 void dfs(int x){ 97 x=makeroot(x); vis[x]=1; 98 calc(x); 99 for(int i=head[x];i;i=e[i].next) 100 if(vis[e[i].u]==0) dfs(e[i].u); 101 } 102 103 int main(){ 104 // freopen("in.txt","r",stdin); 105 // freopen("out.txt","w",stdout); 106 int n; scanf("%d",&n); 107 for(int i=1;i<=n;i++) scanf("%d",num+i); 108 for(int i=1;i<n;i++){ 109 int x,y; scanf("%d%d",&x,&y); 110 add(x,y); add(y,x); 111 } 112 dfs(1); 113 cout<<ans<<endl; 114 }
以上是关于xsy1214 异或路径(xorpath) 点分治+可持久化trie的主要内容,如果未能解决你的问题,请参考以下文章
《算法竞赛进阶指南》0x16Trie POJ3764异或最大路径