题意:给你一棵树(n点),再给你一个k,问想访问k个点最少要走多少边
思路:树的直径d可用两次bfs或者dfs求。若k<=d,则结果为k-1,直接按树的直径走。若k>d,则结果为(d-1)+(k-d)*2,即在走树的直径的过程中走一些旁边的树中的边。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=100011;
int T,n,m,x,y,u,v,dis,ans;
int d[maxn];
vector <int> a[maxn];
void bfs(int v)
{
for(int i=0;i<a[v].size();i++)
{
if(a[v][i]==v || d[a[v][i]]!=0) continue;
d[a[v][i]]=d[v]+1;
bfs(a[v][i]);
}
}
int work(int v)
{
int k,maxx=0;
memset(d,0,sizeof(d));
d[v]=1;
bfs(v);
for(int i=1;i<=n;i++)
if(d[i]>maxx)
{
maxx=d[i];
k=i;
}
return k;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
a[i].clear();
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
a[u].push_back(v);
a[v].push_back(u);
}
x=work(1);
y=work(x);
dis=d[y];
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
if(x<=dis)
ans=x-1;
else
ans=(dis-1)+(x-dis)*2;
printf("%d\n",ans);
}
}
return 0;
}