题意是给一棵树,从一个点出发走k个点,问最少走几次边。
通过一次树DP求出最大直径,如果最大直径能包含k个点就走最大直径,否则每增加一个点就需要多走一条边两次,那么答案就不难想了。
#include <bits/stdc++.h>
using namespace std;
#define maxn 511111
#define maxm 1111111
int dp[maxn][2]; //从i出发到叶子节点的最长长度 次长长度
struct node {
int to, next;
}edge[maxm];
int n, m, head[maxn], cnt;
int Max; //最长链
void add_edge (int from, int to, int i) {
node &e = edge[i];
e.to = to, e.next = head[from], head[from] = i;
}
void dfs (int u, int father) {
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (v == father)
continue;
dfs (v, u);
if (dp[v][0]+1 > dp[u][0]) {
dp[u][1] = dp[u][0];
dp[u][0] = dp[v][0]+1;
}
else if (dp[v][0]+1 > dp[u][1]) {
dp[u][1] = dp[v][0]+1;
}
}
Max = max (dp[u][1]+dp[u][0], Max);
}
int main () {
//freopen ("in", "r", stdin);
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d%d", &n, &m);
cnt = 0;
memset (head, -1, sizeof head);
for (int i = 1; i < n; i++) {
int u, v;
scanf ("%d%d", &u, &v);
add_edge (u, v, cnt++);
add_edge (v, u, cnt++);
}
Max = 0;
memset (dp, 0, sizeof dp);
dfs (1, 0);
int q;
while (m--) {
scanf ("%d", &q);
//cin >> q;
if (q <= Max+1) {
printf ("%d\n", q-1);
}
else {
printf ("%d\n", Max+2*(q-Max-1));
}
}
}
return 0;
}