每日一题Div1 【模板】最小瓶颈生成树(数据加强版)
【模板】最小瓶颈生成树 (最小生成树/LCA)
思路:
就是求出从\(s\rightarrow t\)的路径上最大的边权。
有一个结论: 最小生成树一定是瓶颈生成树
证明:可以采用反证法。 假设最小生成树不是瓶颈树,设最小生成树\(T\)的最大边权为\(e\),则存在一棵瓶颈树\(T_b\),其所有的边的权值小于\(w(e)\)。删除\(T\)中的\(e\),形成两棵树\(T',T''\),用\(T_b\)中连接\(T', T''\)的边连接这两棵树,得到新的生成树,其权值小于\(T\), 与\(T\)是最小生成树矛盾。
因为我们要去求\(s\rightarrow t\)路径上最大权值的边是多少,如果我们选择每一次都去从\(s\)作为起点遍历到\(t\)的话,很明显是会超时的,那么我们可以先求出\(s,t\)的最近公共祖先,然后可以将\(s\rightarrow t\)分成\(s\rightarrow tmp, tmp\rightarrow t\)两个部分,找出这两条路径中最大的边权就可以了。在预处理的时候,我们使用\(fa[u][i]\)来表示\(u\)开始向上\(2^i\)的父节点, \(mx[u][i]\)来表示\(u\)到\(fa[u][i]\)的路径中的最大值。那么我们每一次转移的时候都是从\(fa[u][i - 1]\)转移来的,$$fa[u][i] = fa[fa[u][i - 1]][i - 1]$$ $$mx[u][i] = \max(mx[fa[u][i - 1]][i - 1])$$
\(LCA\)板子:
void dfs(int u, int father) {
dep[u] = dep[father] + 1;
fa[u][0] = father;
for (int i = 1; (1 << i) <= dep[u]; i ++ ) {
fa[u][i] = fa[fa[u][i - 1]][i - 1];
mx[u][i] = std::max(mx[u][i - 1], mx[fa[u][i - 1]][i - 1]);
}
for (auto& [v, w] : G[u]) {
if (v == father) continue;
mx[v][0] = w;
dfs(v, u);
}
}
int lca(int u, int v) {
if (dep[u] > dep[v]) std::swap(u, v);
for (int i = 20; i >= 0; i -- )
if (dep[u] <= dep[v] - (1 << i)) v = fa[v][i];
if (u == v) return u;
for (int i = 20; i >= 0; i -- ) {
if (fa[u][i] == fa[v][i]) continue;
u = fa[u][i], v = fa[v][i];
}
return fa[u][0];
}
在连边的时候,已经连入最小生成树中的点就不需要再连了,来保证我们每一次要加入到已经连起来的点集的点到这个集合的距离最小且没有被这个集合包含,所以我们用并查集来判断是否加入到了集合,加边前进行排序确保每次加进来的边一定是最小的。
std::vector<pii> G[1000010];
struct Edge {
int u, v;
i64 w;
bool operator < (const Edge& W) const {
return w < W.w;
}
}E[1000010];
rep(i,1,m + 1) {
int u, v; i64 w;
read(u), read(v), read(w);
E[i] = {u, v, w};
}
std::sort(E + 1, E + m + 1);
for (int i = 1; i <= m; i ++ ) {
int u = E[i].u, v = E[i].v, w = E[i].w;
if (find(u) == find(v)) continue;
G[u].pb(std::make_pair(v, w));
G[v].pb(std::make_pair(u, w));
merge(u, v);
}
求最大边权的代码:
i64 query(int u, int v) {
i64 ans = hypo;
for (int i = 20; i >= 0; i --) {
if (dep[fa[u][i]] >= dep[v]) {
ans = std::max(ans, mx[u][i]);
u = fa[u][i];
}
}
return ans;
}
int LCA = lca(u, v);
printf("%lld\n",std::max(query(u, LCA), query(v, LCA)));

浙公网安备 33010602011771号