The total number of points obtained is uniquely determined by the first chosen vertex. Therefore, it is sufficient to consider all possible starting vertices, compute the total number of points for each of them, and take the maximum.
Let us run a depth-first search starting from vertex and compute the value weight[v] — the size of the subtree rooted at vertex (i.e., the number of vertices in the subtree of ). Let to_1, to_2, ..., to_k be the children of . Then the following formula holds:
The second depth-first search visits all vertices and allows us to recompute the maximum number of points that can be obtained if the game starts from a given vertex.
Consider the function dfs2. Suppose we are at vertex , and its parent is vertex . If we choose vertex as the first move, then the number of points obtained is .
Make a transition along the edge (v, to) and show how to compute the answer if the game starts from vertex . In fact, we are performing a rerooting of the tree: the root is moved from vertex to vertex .
On the left, a tree rooted at is shown. The vertex is one of its descendants, while is its parent. On the right, the tree is shown rooted at .
To compute weight[to] in the right tree, we need to subtract weight[to] of the left tree from the value and add the number of vertices in the region marked with a dashed line. This number is equal to n - weight[to].
Example
Let the first chosen vertex be . Then the total number of points obtained is .
If the first chosen vertex is , then the number of points obtained is . We move from vertex to vertex as follows: subtract weight[2] = 4 from s = 25 and add (9 - weight[4]) = 5. As a result, we get 25 - 4 + 5 = 26, which is the value of for the tree rooted at vertex .
The maximum number of points is , and it is achieved if the game starts from vertex .
Exercise
Consider the following tree:
Suppose vertex is chosen as the first move. Find the number of points obtained.
Move the root from vertex to vertex and compute the number of points obtained.
Then move the root from to , from to , and from to . Solve each of the resulting cases.
Algorithm implementation
Define the adjacency list of the graph .
vector<vector<int>> g;
vector<int> weight;The function dfs1 performs a depth-first search starting from a vertex whose parent is vertex . During this process, weight[v] is computed — the size of the subtree rooted at vertex , i.e., the number of vertices in this subtree.
void dfs1(int v, int p)
{
weight[v] = 1;
for (int to : g[v])
if (to != p)
{
dfs1(to, v);
weight[v] += weight[to];
}
}The function dfs2 performs a depth-first search starting from a vertex whose parent is vertex . If the first move of the game is to choose vertex , then the number of points obtained is .
void dfs2(int v, int p, long long s)
{
res = max(res, s);
for (int to : g[v])
if (to != p) dfs2(to, v, s - weight[to] + n - weight[to]);
}The main part of the program. Read the input data. Build the graph.
scanf("%d", &n);
g.resize(n + 1);
weight.resize(n + 1);
for (i = 1; i < n; i++)
{
scanf("%d %d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}Start a depth-first search from vertex .
dfs1(1, 0);Compute the sum of all elements in the array weight using the variable . This value is equal to the total number of points obtained if we choose vertex as the first move in the game.
s = 0;
for (i = 1; i <= n; i++)
s += weight[i];Start the second depth-first search from vertex .
dfs2(1, 0, s);Print the answer.
printf("%lld\n", res);