【题解】洛谷 P2052 [NOI2011] 道路修建
链接:洛谷
观察到该图有 \(n\) 个节点, \(n - 1\) 条边,可以发现它是一棵树。
考虑对它进行 dfs,求出对于每一个节点 \(u\),它的子树的节点数量,记为 \(cnt_u\)。由题意,边 \((u, v)\) (\(u\) 在树上的深度小于 \(v\))的费用应该是根节点到 \(u\) 的这条链上的节点个数,与以 \(v\) 为根的子树的节点数的差的绝对值。不难得出,根节点到 \(u\) 的链上的节点个数为: \(cnt_1 - cnt_v\),以 \(v\) 为根的子树的节点数为 \(cnt_v\),所以边 \((u, v)\) 的费用的表达式:
\[\begin{aligned}cost_{(u, v)} = & \;\operatorname{abs}(cnt_1 - cnt_v - cnt_v) \times w_{(u, v)} \\
= & \; \operatorname{abs}(n - cnt_v - cnt_v) \times w_{(u, v)} \\ = & \; \operatorname{abs}(n - 2\times cnt_v) \times w_{(u, v)}\end{aligned}\]
在 dfs 的过程中计算即可。
注意:无向图,开 long long,取绝对值用 llabs。
#include <bits/stdc++.h>
using namespace std;
namespace Prulystic { void Main(); }
int main(){
Prulystic::Main();
return 0;
}
namespace Prulystic{
using ll = long long;
using pll = pair<ll, ll>;
const int N = 2e6 + 5;
ll n, ans, son[N];
vector<pll> g[N];
inline void read(ll& x){
ll s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9') { w = (ch == '-' ? -1 : w); ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
x = s * w;
return;
}
inline void write(ll x){
if(x < 0) { x = -x; putchar('-'); }
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
inline void write(ll x, char ch) { write(x); putchar(ch); }
inline void add(ll a, ll b, ll c){
g[a].push_back({b, c}), g[b].push_back({a, c});
return;
}
void dfs(int u, int f){
son[u] = 1;
for(pll e : g[u]){
ll v = e.first, w = e.second;
if(v == f)
continue;
dfs(v, u);
son[u] += son[v];
ans += llabs(n - 2 * son[v]) * w;
}
return;
}
void Main(){
read(n);
for(int i = 1; i <= n - 1; i++){
ll a, b, c; read(a), read(b), read(c);
add(a, b, c);
}
dfs(1, 0);
write(ans, '\n');
return;
}
}

浙公网安备 33010602011771号