P2726 [SHOI2005] 树的双中心 题解
Description
Solution
对于每个
但是直接暴力求是
注意到深度很小,所以可以考虑
设
容易想到预处理每个点权值最大的儿子,但是这里求总树去掉当前树的连通块的答案时有修改,又注意到一个点最多只有一个儿子的权值会变,所以只要记录权值最大和次大的儿子即可。
时间复杂度:
Code
#include <bits/stdc++.h> // #define int int64_t const int kMaxN = 5e4 + 5; int n; int64_t ans = 1e18, sz[kMaxN], f[kMaxN]; int a[kMaxN], p[kMaxN], dep[kMaxN], wson1[kMaxN], wson2[kMaxN]; std::vector<int> G[kMaxN]; void dfs1(int u, int fa) { sz[u] = a[u], p[u] = fa, dep[u] = dep[fa] + 1; for (auto v : G[u]) { if (v == fa) continue; dfs1(v, u); sz[u] += sz[v], f[u] += f[v] + sz[v]; if (sz[v] >= sz[wson1[u]]) wson2[u] = wson1[u], wson1[u] = v; else if (sz[v] >= sz[wson2[u]]) wson2[u] = v; } } int64_t dfs2(int u, int fa, int64_t now, int64_t sum, int pos) { // 找答案 int v = wson1[u]; if (v == pos || sz[wson2[u]] > sz[v]) v = wson2[u]; if (sz[v] * 2 > sum) return std::min(now, dfs2(v, u, now + (sum - sz[v] * 2), sum, pos)); else return now; } void dfs3(int u, int fa) { for (auto v : G[u]) { if (v == fa) continue; for (int j = u; j; j = p[j]) sz[j] -= sz[v]; ans = std::min(ans, dfs2(v, u, f[v], sz[v], v) + dfs2(1, 0, f[1] - f[v] - (int64_t)(dep[v] - 1) * sz[v], sz[1], v)); for (int j = u; j; j = p[j]) sz[j] += sz[v]; dfs3(v, u); } } void dickdreamer() { std::cin >> n; for (int i = 1; i < n; ++i) { int u, v; std::cin >> u >> v; G[u].emplace_back(v), G[v].emplace_back(u); } for (int i = 1; i <= n; ++i) std::cin >> a[i]; dfs1(1, 0), dfs3(1, 0); std::cout << ans << '\n'; } int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; // std::cin >> T; while (T--) dickdreamer(); // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n"; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步