杂项(大技巧)

Kurskal 重构树

定义

Kurskal 重构树就是在跑 Kurskal 的时候处理出一棵树,这棵树会有一些奇妙的性质。

考虑如何构建。

首先新建 n 个集合,每个集合前有一个节点,点权为 0

每一次加边会合并两个集合,我们就可以新建一个点,点权为加入边的边权,同时将两个集合的根节点分别设为新建点的左右儿子。然后我们把这两个集合和新建点合并成一个集合。新建点设为根。

如此,我们就得到了一棵树。这棵树就叫作 Kurskal 重构树。

举个例子:

image

如上这张图的 Kurskal 生成树就为如下这棵树:

image

性质

由于一共进行了 n1 次加边,即新加入 n1 个点,所以 Kurskal 生成树的点数就为 2n1

不难发现,原图中两个点之间的所有 简单路径上的最大值 的最小值 = 最小生成树上两个点路径上的最大值 = 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

概述

这个东西呢,比较帅。 O(nlogn) 预处理,O(1) 查询。

首先明确 ST 表的功能:O(nlogn) 预处理, O(1) 查询徐建最值。

其次,说一下欧拉序。就是在每次经过这个节点的时候都把他加入到序列末尾。比如这么一棵树,他的欧拉序就是 1,2,3,2,4,5,4,6,4,2,1,7,1。不难发现,n 个点的树的欧拉序长度为 2n1

image

除了欧拉序之外,我们还需要一个 dfs 序(就是长度为 n 的那个)。需要注意,欧拉序和 dfs 序公用一个时间戳。

然后呢,对于两个点 xy,我们找到他们在欧拉序中第一次出现的位置(可以拿 dfs 序直接找到),那么这两个位置之间深度最小的点即为 xy 的 lca。

接下来随便怎么搞一搞就好了。

参考代码

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])];
}
posted @   Zctf1088  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示