AT_cf17_final_j Tree MST 题解
一个有趣的结论是,一个图,选出若干个边集,满足他们的并为原图边集。则必有他们每个集合的 MST 的边的并,再求一次 MST 为原图的 MST。
考虑点分治,设当前重心为
每次分治时,把
#include <bits/stdc++.h>
using namespace std;
#define int long long
constexpr int N = 2e5 + 5, M = N * 20;
int n;
vector<int> w;
vector<vector<pair<int, int>>> G;
vector<int> dis, sz;
bitset<N> del;
struct Edge
{
int u, v, w;
Edge(int _u, int _v, int _w): u(_u), v(_v), w(_w){}
Edge(){}
};
vector<Edge> eg;
set<pair<int, int> > cv;
int tot, wc;
auto get_sz(int u, int f) -> void
{
sz[u] = 0;
if (del[u]) return;
sz[u] = 1;
for (auto &j : G[u])
{
if (j.first != f)
{
get_sz(j.first, u);
sz[u] += sz[j.first];
}
}
}
auto get_wc(int u, int f) -> void
{
if (del[u]) return;
int maxn = tot - sz[u];
for (auto &j : G[u])
{
if (j.first ^ f)
{
get_wc(j.first, u);
maxn = max(maxn, sz[j.first]);
}
}
if (maxn <= (tot >> 1)) wc = u;
}
vector<int> total;
auto get_dist(int u, int f, int w) -> void
{
dis[u] = 0;
if (del[u]) return;
total.emplace_back(u);
dis[u] = dis[f] + w;
for (auto &j : G[u])
{
if (j.first != f)
{
get_dist(j.first, u, j.second);
}
}
}
auto solve(int u) -> void
{
if (del[u]) return;
cv.clear();
get_sz(u, 0);
tot = sz[u];
wc = u;
get_wc(u, 0);
u = wc;
del[u] = 1;
dis[u] = 0;
for (auto &j : G[u])
{
if (del[j.first]) continue;
total.clear();
total.shrink_to_fit();
get_dist(j.first, u, j.second);
vector<pair<int, int> > djb;
for (auto &k : total)
{
dis[k] += w[k];
djb.emplace_back(make_pair(dis[k], k));
}
for (auto &k : djb)
{
cv.insert(make_pair(k.first, k.second));
}
}
for (auto it = cv.begin(); it != cv.end(); ++it)
{
if (it != cv.begin())
{
eg.emplace_back(Edge((*it).second, (*(cv.begin())).second, (*it).first + (*(cv.begin())).first));
}
eg.emplace_back(u, (*(it)).second, (*it).first + w[u]);
}
for (auto &j : G[u]) solve(j.first);
}
class Union_Find
{
public:
vector<int> fa;
auto Init() -> void
{
fa.resize(n + 1);
for (int i = 0; i <= n; i++) fa[i] = i;
}
auto find(int u) -> int
{
return (fa[u] == u ? u : fa[u] = find(fa[u]));
}
auto merge(int u, int v) -> void
{
fa.at(find(u)) = find(v);
}
}uf;
auto main() -> signed
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
del.reset();
w.resize(n + 1);
dis.resize(n + 1);
sz.resize(n + 1);
G.resize(n + 1);
for (int i = 1; i <= n; i++) cin >> w[i];
for (int i = 1; i < n; i++)
{
int u, v, w;
cin >> u >> v >> w;
G[u].emplace_back(make_pair(v, w));
G[v].emplace_back(make_pair(u, w));
}
solve(1);
uf.Init();
long long ans = 0LL;
sort(eg.begin(), eg.end(), [&](const Edge& x, const Edge& y){return x.w < y.w;});
for (int i = 0; i < eg.size(); i++)
{
auto p = eg.operator[](i);
if (uf.find(p.u) ^ uf.find(p.v))
{
ans += p.w;
uf.merge(p.u, p.v);
}
}
cout << ans << "\n";
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现