Solution
Initially, the road network is a tree. We need to add one edge between two non-adjacent vertices to minimize the total damage caused by removing each original edge independently.
Consider adding an edge between vertices and .
Since the original graph is a tree, there is exactly one simple path between and . Adding the new edge creates a cycle consisting of this path and the new edge.
If we remove an original edge belonging to this cycle, the graph remains connected, so the damage is .
Otherwise, removing an original edge splits the graph into two connected components. If their sizes are and n-s, the damage equals
Notice that this value does not depend on which new edge we add, as long as the removed edge does not belong to the created cycle.
Root the original tree at vertex and let sz_v denote the size of the subtree of vertex .
For every edge connecting a vertex to its parent, assign the weight
Let be the sum of weights of all original edges:
If we add an edge between vertices and , all original edges on the path between them become part of the cycle and contribute to the total damage.
Therefore, the resulting total damage is
Thus, minimizing the total damage is equivalent to finding a path with the maximum possible sum of edge weights.
This is exactly the problem of finding the weighted diameter of a tree.
Let denote the maximum sum of edge weights along any simple path. Then the answer is
Since all edge weights are positive and n\ge 3, a weighted diameter contains at least two edges. Therefore, its endpoints are not adjacent, so adding an edge between them is always allowed.
We can find the weighted diameter using dynamic programming on the tree.
Let dp_v be the maximum sum of edge weights along a path starting at vertex and going down into its subtree.
For every child of vertex , consider
Let best_1 and best_2 be the two largest values among these candidates, using if there are fewer than two children.
Then
The maximum-weight path whose highest vertex is has weight
Therefore, the weighted diameter is
We calculate subtree sizes, the total weight , and the weighted diameter in a single bottom-up traversal of the rooted tree.
Complexity Analysis
Building the rooted tree takes time. Each edge is processed a constant number of times when calculating subtree sizes and the weighted diameter.
Therefore, the total time complexity is , and the space complexity is .
Implementation
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve() {
int n;
cin >> n;
vector<vector<int>> g(n + 1);
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> par(n + 1), order;
order.push_back(1);
for (int i = 0; i < (int)order.size(); i++) {
int v = order[i];
for (int u : g[v]) {
if (u == par[v]) continue;
par[u] = v;
order.push_back(u);
}
}
vector<int> sz(n + 1, 1);
vector<ll> dp(n + 1);
ll sum = 0, diam = 0;
for (int i = n - 1; i >= 0; i--) {
int v = order[i];
ll best1 = 0, best2 = 0;
for (int u : g[v]) {
if (par[u] != v) continue;
sz[v] += sz[u];
ll w = min(sz[u], n - sz[u]);
sum += w;
ll cur = dp[u] + w;
if (cur > best1) {
best2 = best1;
best1 = cur;
} else if (cur > best2) {
best2 = cur;
}
}
dp[v] = best1;
diam = max(diam, best1 + best2);
}
cout << sum - diam << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
}