最小异或生成树学习笔记
最近打的区域赛模拟里用到了最小异或生成树
于是进行了一手学习(
问题背景:
有一个序列,每个点有一个权值。
取一条边 -> 的代价是
问这个图的最小生成树的边权和
前置知识
trie树
算法原理
1、Borůvka算法(用于求解最小生成树)
做法:
开始时,每个点都是一个独立的连通块。每次对于一个连通块,去找最短边,其中边的一个端点在连通块内,而另一个不在,将这些边加入答案的最小生成树中,并且用并查集更新联通状态,直到没有边可以添加。
效率分析:
每次联通块的数量至少会减半,而每次询问要访问整个边集
所以总复杂度是
2、最小异或生成树
题目中求解最小生成树,如果按照kruskal来的话需要把所有边都列出来,是的效率,显然会T飞
考虑把序列中的数字按照从高位到低位分组,按照该位置是0还是1来分
这个和字典树的操作正好对应
于是我们就发现,如果我们每次要把两个点接起来的话,显然在同一个lca的子树内是最优的,因为它高位的异或全部是,如果离开这个子树而去取其他子树的点的话,则一定会在更高位置产生贡献,答案不会更优
发现现在问题就变成了 让左子树联通,右子树联通 然后让左右子树联通
左子树和右子树显然是原问题的子问题,现在考虑第三个问题要怎么解决
类似于dfs序的考虑,我们在对这个字典树进行先根遍历的时候,得到的序列正好是从小到大的
于是我们可以先对序列进行排序,此时每个点的子树里所包含的数字反映在原序列上就是一段连续的区间
每次合并左右子树的时候,暴力的把比较小的子树中的每一个权值在另一个trie树上跑即可(求最大/最小异或,trie的经典操作)
3、题目
模板,就是问题背景描述的问题
#include<bits/stdc++.h> using namespace std; int N,cnt; int a[200005],L[31*200005],R[31*200005],Tree[31*200005][3]; void Insert(long long x,int pos){ int Now=0; for (int i=30;i>=0;i--){ if ((x>>i)&1ll){ int &nw=Tree[Now][1]; if (!nw) nw=++cnt; if (!L[nw]) L[nw]=pos; R[nw]=pos; Now=nw; } else{ int &nw=Tree[Now][0]; if (!nw) nw=++cnt; if (!L[nw]) L[nw]=pos; R[nw]=pos; Now=nw; } } } long long query(int Now,int pos,long long x){ long long ans=0; for (int i=pos;i>=0;i--){ int nw=((x>>i)&1); if (Tree[Now][nw]) Now=Tree[Now][nw]; else Now=Tree[Now][nw^1],ans+=(1ll<<i); } return ans; } long long Getans(int rt,int pos){ int x=Tree[rt][0],y=Tree[rt][1]; if (!x&&y) return Getans(y,pos-1); else if (!y&&x) return Getans(x,pos-1); else if (x&&y) { int xx=R[x]-L[x]+1,yy=R[y]-L[y]+1; long long ans=1e9+7; if (xx<=yy){ for (int i=L[x];i<=R[x];i++){ ans=min(ans,query(y,pos-1,a[i])+(1ll<<pos)); } } else { for (int i=L[y];i<=R[y];i++) ans=min(ans,query(x,pos-1,a[i])+(1ll<<pos)); } return Getans(x,pos-1)+Getans(y,pos-1)+ans; } if (pos==0) return 0; } int main(){ scanf("%d",&N); for (int i=1;i<=N;i++) scanf("%d",&a[i]); sort(a+1,a+N+1); for (int i=1;i<=N;i++) Insert(a[i],i); printf("%lld\n",Getans(0,30)); return 0; }
干啥啥不行
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?