【xsy1122】 路径 点分治+trie
题目大意:给你一棵n个点的树,树边上有边权,对于每一个点,你要求出经过该点的所有的路径中,路径异或和最大的值。
数据范围:n≤105,边权≤109。
我们考虑枚举每一条路径,显然这个是会T的,于是我们用点分治来实现这个过程。
对于一棵以x为根的子树,假设它有k个儿子,编号v1....k。
我们维护一棵trie树,记录所有从根到以v1,v2.....vp为跟的子树中的路径长度。
对于从跟到第p+1个儿子为跟的树中的每一条路径,我们都丢到trie树中查询与最大的异或值。
在查询最大值的过程中,我们维护一个maxi,表示从根到i的路径上的最大路径异或和。我们可以通过简单的标记上传去实现更新。
然后再将所有终点在p+1个子树中的路径加入到trie树种。
时间复杂度:O(n log n log v)。
1 #include<bits/stdc++.h> 2 #define M 100005 3 #define INF ((1<<31)-1) 4 using namespace std; 5 6 struct edge{int u,v,next;}e[M*2]={0}; int head[M]={0},Use=0; 7 void add(int x,int y,int z){Use++;e[Use].u=y;e[Use].v=z;e[Use].next=head[x];head[x]=Use;} 8 9 int use=1; 10 struct trie{int a[2];}a[M*30]={0}; 11 void add(int x){ 12 int now=1; 13 for(int i=30;~i;i--){ 14 bool k=(1<<i)&x; 15 if(a[now].a[k]) now=a[now].a[k]; 16 else a[now].a[k]=++use,a[use].a[0]=a[use].a[1]=0,now=use; 17 } 18 } 19 int query(int x){ 20 int now=1,res=0; 21 for(int i=30;~i;i--){ 22 bool k=(1<<i)&x; 23 if(a[now].a[k^1]) now=a[now].a[k^1],res+=(1<<i); 24 else now=a[now].a[k]; 25 } 26 return res; 27 } 28 29 int siz[M]={0},vis[M]={0}; 30 int minn=INF,minid=0; 31 void dfssiz(int x,int fa){ 32 siz[x]=1; 33 for(int i=head[x];i;i=e[i].next) 34 if(e[i].u!=fa&&vis[e[i].u]==0) 35 dfssiz(e[i].u,x),siz[x]+=siz[e[i].u]; 36 } 37 void dfsmax(int x,int fa,int fsiz){ 38 int maxn=fsiz-siz[x]; 39 for(int i=head[x];i;i=e[i].next) 40 if(e[i].u!=fa&&vis[e[i].u]==0){ 41 dfsmax(e[i].u,x,fsiz); 42 maxn=max(maxn,siz[e[i].u]); 43 } 44 if(maxn<minn) minn=maxn,minid=x; 45 } 46 int makeroot(int x){ 47 dfssiz(x,0); 48 minn=INF; minid=0; 49 dfsmax(x,0,siz[x]); 50 return minid; 51 } 52 53 int ans[M]={0},now[M]={0}; 54 void upans(int x,int fa,int Val){ 55 int hh=query(Val); 56 now[x]=hh; 57 for(int i=head[x];i;i=e[i].next) 58 if(e[i].u!=fa&&vis[e[i].u]==0){ 59 upans(e[i].u,x,Val^e[i].v); 60 now[x]=max(now[x],now[e[i].u]); 61 } 62 ans[x]=max(ans[x],now[x]); 63 } 64 void addtrie(int x,int fa,int Val){ 65 add(Val); 66 for(int i=head[x];i;i=e[i].next) 67 if(e[i].u!=fa&&vis[e[i].u]==0){ 68 addtrie(e[i].u,x,Val^e[i].v); 69 } 70 } 71 72 stack<int> s; 73 void dfs(int x){ 74 x=makeroot(x); vis[x]=1; 75 76 a[1].a[0]=a[1].a[1]=0; use=1; 77 add(0); 78 for(int i=head[x];i;i=e[i].next) if(vis[e[i].u]==0){ 79 upans(e[i].u,x,e[i].v); 80 ans[x]=max(ans[x],now[e[i].u]); 81 addtrie(e[i].u,x,e[i].v); 82 s.push(i); 83 } 84 85 a[1].a[0]=a[1].a[1]=0; use=1; 86 add(0); 87 while(!s.empty()){ 88 int i=s.top(); s.pop(); 89 upans(e[i].u,x,e[i].v); 90 ans[x]=max(ans[x],now[e[i].u]); 91 addtrie(e[i].u,x,e[i].v); 92 } 93 94 for(int i=head[x];i;i=e[i].next) if(vis[e[i].u]==0) 95 dfs(e[i].u); 96 } 97 98 int main(){ 99 int n; scanf("%d",&n); 100 for(int i=1;i<n;i++){ 101 int x,y,z; scanf("%d%d%d",&x,&y,&z); 102 add(x,y,z); add(y,x,z); 103 } 104 dfs(1); 105 for(int i=1;i<=n;i++) printf("%d\n",ans[i]); 106 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!