题意:
一棵树,问从任意点出发,访问k个点走过的最少的边数。
题解:
找一条树上最长链,当k大于链上的点数时,就要走一些链的节点的子树且走回链上,即子树的边走了两次。
//Time:765ms
//Memory:2644KB
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#define MAXN 200010
using namespace std;
int mlen;
int he[MAXN],to[MAXN],nex[MAXN],top;
void add(int u,int v)
{
to[top]=v;
nex[top]=he[u];
he[u]=top++;
}
int dfs(int h,int fa)
{
int on=0,tw=0,tmp;
for(int i=he[h];i!=-1;i=nex[i])
if(to[i]!=fa)
{
tmp=dfs(to[i],h)+1;
if(tmp>on)
{
tw=on;
on=tmp;
}
else if(tmp>tw)
tw=tmp;
}
mlen=max(mlen,tw+on);
return on;
}
int main()
{
//freopen("/home/moor/Code/input","r",stdin);
int ncase,n,m;
scanf("%d",&ncase);
while(ncase--)
{
top=0;
memset(he,-1,sizeof(he));
scanf("%d%d",&n,&m);
for(int i=0;i<n-1;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
mlen=0;
dfs(1,-1);
++mlen;
for(int i=0;i<m;++i)
{
int k;
scanf("%d",&k);
if(k<=mlen) printf("%d\n",k-1);
else printf("%d\n",mlen-1+(k-mlen)*2);
}
}
return 0;
}