欢迎来到下蛋爷之家|

下蛋爷

园龄:4年2个月粉丝:8关注:23

P2726 [SHOI2005] 树的双中心 题解

Description

n5×104,树的深度 100

Solution

对于每个 x,y,满足 d(v,x)d(v,y) 或者 d(v,x)d(v,y) 的点一定构成一个子树,所以可以枚举这个子树的根,然后对两边分别求重心可以得到答案。

但是直接暴力求是 O(n2) 的,过不了。

注意到深度很小,所以可以考虑 O(h) 求一颗树的重心。

szi 表示以 i 为根的子树权值的和,假设已知节点 u 到其他点的距离和 now,那么对于 u 的儿子 v 的答案就是 now+szroot2×szv,所以每次只用跳到子树权值最大的儿子 v,如果答案不会变优就终止即可。

容易想到预处理每个点权值最大的儿子,但是这里求总树去掉当前树的连通块的答案时有修改,又注意到一个点最多只有一个儿子的权值会变,所以只要记录权值最大和次大的儿子即可。

时间复杂度:O(nh)

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;
}
posted @   下蛋爷  阅读(12)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起