F. Gardening Friends

发布时间 2023-04-26 16:52:13作者: onlyblues

F. Gardening Friends

Two friends, Alisa and Yuki, planted a tree with $n$ vertices in their garden. A tree is an undirected graph without cycles, loops, or multiple edges. Each edge in this tree has a length of $k$. Initially, vertex $1$ is the root of the tree.

Alisa and Yuki are growing the tree not just for fun, they want to sell it. The cost of the tree is defined as the maximum distance from the root to a vertex among all vertices of the tree. The distance between two vertices $u$ and $v$ is the sum of the lengths of the edges on the path from $u$ to $v$.

The girls took a course in gardening, so they know how to modify the tree. Alisa and Yuki can spend $c$ coins to shift the root of the tree to one of the neighbors of the current root. This operation can be performed any number of times (possibly zero). Note that the structure of the tree is left unchanged; the only change is which vertex is the root.

The friends want to sell the tree with the maximum profit. The profit is defined as the difference between the cost of the tree and the total cost of operations. The profit is cost of the tree minus the total cost of operations.

Help the girls and find the maximum profit they can get by applying operations to the tree any number of times (possibly zero).

Input

The first line of the input contains one integer $t$ ($1 \le t \le 10^4$) — the number of test cases.

The description of the test cases follows.

The first line of each test case contains integers $n$, $k$, $c$ ($2 \le n \le 2 \cdot 10^5$; $1 \le k, c \le 10^9$) — the number of vertices in the tree, the length of each edge, and the cost of the operation.

The next $n - 1$ lines of the test case contain pairs of integers $u_i$, $v_i$ ($1 \le u_i, v_i \le n$) — the edges of the graph. These edges form a tree.

The sum of the values of $n$ over all test cases does not exceed $2 \cdot 10^5$.

Output

For each test case, output a single integer — the maximum profit that Yuki and Alisa can get.

Example

input

4
3 2 3
2 1
3 1
5 4 1
2 1
4 2
5 4
3 4
6 5 3
4 1
6 1
2 6
5 1
3 2
10 6 4
1 3
1 9
9 7
7 6
6 4
9 2
2 8
8 5
5 10

output

2
12
17
32

 

解题思路

  还是很容易想到暴力做法的,就是考虑把$1 \sim n$中每个节点$u$都变成根,然后求从根节点$u$到其他点的最长路径$d$,以及从变到根节点所需要的交换次数$\text{dep}$,那么以$u$为根的最大利益就是$d \cdot k - \text{dep} \cdot c$。然后枚举所有的情况取最大值就好了。

  其中将节点$u$变换到根节点所需要的交换次数就是初始树中从$1$到$u$的深度大小。

  其实分析到这里就很容易想到换根dp,所以这题其实还蛮简单的。然后还有利用树的直径的性质来做的,这里先给出换根dp的做法。

  对于以$1$为根的树,定义$d_1[u]$表示从$u$往下能走到的最远距离,$d_2[u]$表示从$u$往下能走到的次远距离(非严格,即允许$d_1[u] = d_2[u]$)。定义$\text{son}[u]$表示从$u$的哪个子节点往下走能得到最远距离,换句话来说从$\text{son}[u]$往下走能得到$d_1[u]$。定义$\text{up}[u]$表示从$u$的父节点往上走能走到的最远距离。

  其中$d_1[u]$,$d_2[u]$和$\text{son}[u]$的求法很简单,只需要一次dfs就可以维护出这些信息,不再多说。

  对于$\text{up}[u]$的求法,先画个图:

  很明显如果$\text{son}[fa] \ne u$,即$fa$从子节点$u$往下走得不到最远距离,那么有$\text{up}[u] = \max \{ d_1[fa], \text{up}[fa] \} + 1$。否则如果$\text{son}[fa] = u$,那么从$u$往上走然后再下走就又走到$u$了,因此有$\text{up}[u] = \max \{ d_2[fa], \text{up}[fa] \} + 1$.

  最后如果要把$u$变到根节点,那么从$u$出发能到达的最远距离就是$\max \{ d_1[i], d_2[i], \text{up}[i] \}$。然后枚举每一个$u$,计算$\max \{ d1[u], d2[u], up[u] \} \cdot k - dep[u] \cdot c$,并取最大值。

  AC代码如下,时间复杂度为$O(n)$:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 2e5 + 10, M = N * 2;
 7 
 8 int head[N], e[M], ne[M], idx;
 9 int dep[N], d1[N], d2[N], up[N], son[N];
10 
11 void add(int v, int w) {
12     e[idx] = w, ne[idx] = head[v], head[v] = idx++;
13 }
14 
15 void dfs_d(int u, int pre, int d) {
16     dep[u] = d;
17     d1[u] = d2[u] = 0;
18     for (int i = head[u]; i != -1; i = ne[i]) {
19         if (e[i] != pre) {
20             dfs_d(e[i], u, d + 1);
21             int t = d1[e[i]] + 1;
22             if (t >= d1[u]) d2[u] = d1[u], d1[u] = t, son[u] = e[i];
23             else if (t > d2[u]) d2[u] = t;
24         }
25     }
26 }
27 
28 void dfs_up(int u, int pre) {
29     for (int i = head[u]; i != -1; i = ne[i]) {
30         if (e[i] != pre) {
31             if (son[u] == e[i]) up[e[i]] = max(up[u], d2[u]) + 1;
32             else up[e[i]] = max(up[u], d1[u]) + 1;
33             dfs_up(e[i], u);
34         }
35     }
36 }
37 
38 void solve() {
39     int n, k, c;
40     scanf("%d %d %d", &n, &k, &c);
41     memset(head, -1, sizeof(head));
42     idx = 0;
43     for (int i = 0; i < n - 1; i++) {
44         int v, w;
45         scanf("%d %d", &v, &w);
46         add(v, w), add(w, v);
47     }
48     dfs_d(1, -1, 0);
49     dfs_up(1, -1);
50     LL ret = 0;
51     for (int i = 1; i <= n; i++) {
52         ret = max(ret, 1ll * k * max({d1[i], d2[i], up[i]}) - 1ll * c * dep[i]);
53     }
54     printf("%lld\n", ret);
55 }
56 
57 int main() {
58     int t;
59     scanf("%d", &t);
60     while (t--) {
61         solve();
62     }
63     
64     return 0;
65 }

  再给出另外一种做法。首先需要知道性质:已知树的直径的两个端点为$x$和$y$,那么树中任意一点所能走到的最远的点必然是$x$和$y$中的一个。证明可以参考链接

  因此可以先通过两次dfs找到树的直径的两个端点$x$与$y$,然后求树中所有点到$x$与$y$的距离,取两者中的最大值,就是该节点所能走到其他点的最大距离。最后枚举所有的$u$,求$d_{\max}[u] \cdot k - dep[u] \cdot c$并取最大值。

  AC代码如下,时间复杂度为$O(n)$:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 2e5 + 10, M = N * 2;
 7 
 8 int head[N], e[M], ne[M], idx;
 9 int dep[N], d1[N], d2[N];
10 
11 void add(int v, int w) {
12     e[idx] = w, ne[idx] = head[v], head[v] = idx++;
13 }
14 
15 void dfs(int u, int pre, int *d) {
16     for (int i = head[u]; i != -1; i = ne[i]) {
17         if (e[i] != pre) {
18             d[e[i]] = d[u] + 1;
19             dfs(e[i], u, d);
20         }
21     }
22 }
23 
24 void solve() {
25     int n, k, c;
26     scanf("%d %d %d", &n, &k, &c);
27     memset(head, -1, sizeof(head));
28     idx = 0;
29     for (int i = 0; i < n - 1; i++) {
30         int v, w;
31         scanf("%d %d", &v, &w);
32         add(v, w), add(w, v);
33     }
34     dep[1] = 0;
35     dfs(1, -1, dep);
36     int x = max_element(dep + 1, dep + n + 1) - dep;
37     d1[x] = 0;
38     dfs(x, -1, d1);
39     int y = max_element(d1, d1 + n + 1) - d1;
40     d2[y] = 0;
41     dfs(y, -1, d2);
42     LL ret = 0;
43     for (int i = 1; i <= n; i++) {
44         ret = max(ret, 1ll * max(d1[i], d2[i]) * k - 1ll * dep[i] * c);
45     }
46     printf("%lld\n", ret);
47 }
48 
49 int main() {
50     int t;
51     scanf("%d", &t);
52     while (t--) {
53         solve();
54     }
55     
56     return 0;
57 }

 

参考资料

  Codeforces Round #867 (Div. 3) Editorial:https://codeforces.com/blog/entry/115409

  Codeforces Round 867 (Div. 3) A - G:https://zhuanlan.zhihu.com/p/624648254