【xsy1214】 异或路径(xorpath) 点分治+可持久化trie
题目大意:给你一棵n个点的树,每个点有一个点权x,问你所有路径中点权异或和最大的路径的异或和
数据范围:n≤30000,x≤231−1。
如果是边上有点权的话非常简单,直接一个trie就可以水过去了。
然而这题是点权,非常烦人。我们考虑用点分治去解决。
假设当前需要遍历的树的重心是x,我们开一个可持久化trie,我们用son[x][i]表示x的第i个儿子(我们假设总共有px个),将从son[x][i]出发的路径异或和加入第[i,px]个trie树中,当我们遍历出一条从x出发,经过son[x][i]的路径时,我们把这个路径的异或和放入第i−1个trie树中进行搜索。
我们已知点分治的时间复杂度是O(n log n),由于这里面套了一个可持久化trie,那么时间复杂度就是O(n log n logmaxx2。
然后我的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 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 用 C# 插值字符串处理器写一个 sscanf
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!