杂项(大技巧)
Kurskal 重构树
定义
Kurskal 重构树就是在跑 Kurskal 的时候处理出一棵树,这棵树会有一些奇妙的性质。
考虑如何构建。
首先新建
每一次加边会合并两个集合,我们就可以新建一个点,点权为加入边的边权,同时将两个集合的根节点分别设为新建点的左右儿子。然后我们把这两个集合和新建点合并成一个集合。新建点设为根。
如此,我们就得到了一棵树。这棵树就叫作 Kurskal 重构树。
举个例子:
如上这张图的 Kurskal 生成树就为如下这棵树:
性质
由于一共进行了
不难发现,原图中两个点之间的所有 简单路径上的最大值 的最小值 = 最小生成树上两个点路径上的最大值 = Kurskal 生成树上两个点的 LCA 的点权。
参考代码
for (int i = 1; i <= n; i++) fa[i] = i, rt[i] = i;
tot = n;
for (int i = 1; i <= m; i++) {
int x = getfa(e[i].x), y = getfa(e[i].y);
if (x != y) {
fa[y] = x;
tot++;
G[tot].push_back(rt[x]);
G[tot].push_back(rt[y]);
rt[x] = rt[y] = tot;
val[tot] = e[i].w;
}
}
ST 表 + 欧拉序求 LCA
概述
这个东西呢,比较帅。
首先明确 ST 表的功能:
其次,说一下欧拉序。就是在每次经过这个节点的时候都把他加入到序列末尾。比如这么一棵树,他的欧拉序就是
除了欧拉序之外,我们还需要一个 dfs 序(就是长度为
然后呢,对于两个点
接下来随便怎么搞一搞就好了。
参考代码
int dfn[N], id[2 * N], tot;
void dfs(int x) {
id[++tot] = x;
dfn[x] = tot;
for (int y : G[x]) {
dfs(y);
id[++tot] = x;
}
}
int Log2[2 * N], f[2 * N][18];
void init() {
for (int i = 2; i <= tot; i++) Log2[i] = Log2[i / 2] + 1;
for (int i = 1; i <= tot; i++) f[i][0] = dfn[id[i]];
for (int j = 1; j <= Log2[tot]; j++) {
for (int i = 1; i + (1 << j) - 1 <= tot; i++) {
f[i][j] = min(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}
}
}
int getlca(int x, int y) {
if (dfn[x] > dfn[y]) swap(x, y);
int s = Log2[dfn[y] - dfn[x] + 1];
return id[min(f[dfn[x]][s], f[dfn[y] - (1 << s) + 1][s])];
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】