Given a tree with n vertices, we want to add an edge between vertex 1 and vertex x, so that the sum of d(1, v) for all vertices v in the tree is minimized, where d(u, v) is the minimum number of edges needed to pass from vertex u to vertex v. Do you know which vertex x we should choose?
Recall that a tree is an undirected connected graph with n vertices and n - 1 edges.
InputThere are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains an integer n (1 ≤ n ≤ 2 × 105), indicating the number of vertices in the tree.
Each of the following n - 1 lines contains two integers u and v (1 ≤ u, v ≤ n), indicating that there is an edge between vertex u and v in the tree.
It is guaranteed that the given graph is a tree, and the sum of n over all test cases does not exceed 5 × 105. As the stack space of the online judge system is not very large, the maximum depth of the input tree is limited to about 3 × 104.
We kindly remind you that this problem contains large I/O file, so it's recommended to use a faster I/O method. For example, you can use scanf/printf instead of cin/cout in C++.
<h4< dd="">OutputFor each test case, output a single integer indicating the minimum sum of d(1, v) for all vertices v in the tree (NOT the vertex x you choose).
<h4< dd="">Sample Input2 6 1 2 2 3 3 4 3 5 3 6 3 1 2 2 3<h4< dd="">Sample Output
8 2
<h4< dd="">
Hint
For the first test case, if we choose x = 3, we will have
d(1, 1) + d(1, 2) + d(1, 3) + d(1, 4) + d(1, 5) + d(1, 6) = 0 + 1 + 1 + 2 + 2 + 2 = 8
It's easy to prove that this is the smallest sum we can achieve.
题意:首先给你n个点, 然后给你n - 1条边, 这n - 1条边形成一棵树, 定义d(1, v)表示1这个点到v这个点之间的距离, 之后你有一个操作, 可以额外多连一条边, 这条边可以连在1于任意一个点上, 之后问d(1, 2) + d(1, 3) + ........ + d(1, n), 并让其最小;
思路:看到这个之后很本能的反应就是每个点都与1加一条边, 然后取个最小值嘛, 但是会不会复杂度高呢? 不然, 这里有个很重要的点就是按深度来更新, 从当前点更新这个点的下一个节点, 那么只会影响到当前点深度的一半处的点, 这个画一下图就可以看出来, 之后我们只需要记录每一个深度有多少个点, 每一个点有多少个子节点, 这样我们就可以按深度自顶向下进行更新了, 具体看代码就好了;
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxed = 200000 + 10;
typedef long long ll;
struct E
{
int v, bef;
}e[maxed * 2];
int n, ans, head[maxed];
ll dp[maxed], size_[maxed], d[maxed];
int main()
{
void add_(int x, int y);
void slove_1(int u, int fa);
void slove_2(int u, int fa, int dep);
int N;
scanf("%d", &N);
while (N--) {
ans = 1;
memset(head, -1, sizeof(head));
scanf("%d", &n);
int a, b;
for (int i = 1; i <= n - 1; ++i) {
scanf("%d%d", &a, &b);
add_(a, b);
add_(b, a);
}
dp[1] = 0;
slove_1(1, 1);
slove_2(1, 1, 0);
ll answer = dp[1];
for (int i = 2; i <= n; ++i)
answer = min(answer, dp[i]);
printf("%lld\n", answer);
}
return 0;
}
void add_(int x, int y)
{
e[ans].v = y;
e[ans].bef = head[x];
head[x] = ans++;
}
void slove_1(int u, int fa)
{
size_[u] = 1;
for (int i = head[u]; i != -1; i = e[i].bef) {
int v = e[i].v;
if (v == fa)
continue;
slove_1(v, u);
size_[u] += size_[v];
dp[1] += size_[v];
}
}
void slove_2(int u, int fa, int dep)
{
d[dep] = size_[u];
for (int i = head[u]; i != -1; i = e[i].bef) {
int v = e[i].v;
if (v == fa)
continue;
d[dep + 1] = size_[v];
if (u == 1)
dp[v] = dp[u];
else {
if (dep % 2)
dp[v] = dp[u] + d[(dep + 1) / 2 + 1] - 2 * size_[v];
else
dp[v] = dp[u] + d[dep / 2 + 1] - 2 * size_[v];
}
slove_2(v, u, dep + 1);
}
}