[洛谷 P1131 ZJOI2007] 时态同步
题目链接
大致题意:
n个点,n-1条边的无向树,根节点为s,每一条边有代价w
加上最小的代价把所有叶子节点到根节点的距离调为相同
解题思路:
贪心去想怎样花费的代价最小呢,肯定是调整一次边,可以对多个叶子节点产生影响
所以,调整越靠近根节点的边最终的代价越小
例如
以这种方式,就可以保证用最小的代价把所有叶子节点调整到同一深度
定义状态方程:f[i]表示从i到i的子树的叶子节点的最长距离
每次调整的代价为 f[u]-(f[v]+w) (w为u到v的边权)
每次累加代价即可
AC代码:
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
const int N = 5e5 + 10;
vector<pair<int, int>>e[N];
ll f[N], res; //f[i]表示从i到i的子树中的叶子节点的最长距离
void dfs(int u, int fa) {
for (auto& op : e[u]) {
int v = op.first, w = op.second;
if (v == fa)continue;
dfs(v, u);
f[u] = max(f[u], f[v] + w);
}
for (auto& op : e[u]) {
int v = op.first, w = op.second;
if (v == fa)continue;
res += f[u] - (f[v] + w);
}
}
int main(void)
{
int n, s; cin >> n >> s;
for (int i = 1; i < n; ++i) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
e[a].push_back({ b,c });
e[b].push_back({ a,c });
}
dfs(s, -1);
cout << res << endl;
return 0;
}