题目链接
Claire and her little friend, ykwd, are travelling in Shevchenko's Park! The park is beautiful - but large, indeed. N feature spots in the park are connected by exactly (N-1) undirected paths, and Claire is too tired to visit all of them. After consideration, she decides to visit only K spots among them. She takes out a map of the park, and luckily, finds that there're entrances at each feature spot! Claire wants to choose an entrance, and find a way of visit to minimize the distance she has to walk. For convenience, we can assume the length of all paths are 1.
Claire is too tired. Can you help her?
Input
An integer T(T≤20) will exist in the first line of input, indicating the number of test cases.
Each test case begins with two integers N and M(1≤N,M≤10 5), which respectively denotes the number of nodes and queries.
The following (N-1) lines, each with a pair of integers (u,v), describe the tree edges.
The following M lines, each with an integer K(1≤K≤N), describe the queries.
The nodes are labeled from 1 to N.
Output
For each query, output the minimum walking distance, one per line.
Sample Input
1 4 2 3 2 1 2 4 2 2 4
Sample Output
1 4
PS:题意:一个人去逛公园,想逛k个地方,但是不想走路。要求求出最少走的路的长度。
首先做这个题的时候我们要考虑树的直径,因为要是想逛的步数k小于直径上的点数这样步数是最少的,为k-1步。现在我们要考虑要走的点数大于树的直径的情况,在这种情况下,我们就要考虑走到叶子节点后要往回走。其实这个问题很容易思考到,我们还是要先走数的直径,走完了过后,再往回走,往回走一个首先要回来再走到那个节点,等于每个节点要走两段才能到达所以当k大于直径的时候最短步数len-1+(k-1)*2;len为树的直径上的节点数。
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e5+10;
const int mod=10007;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
typedef long long ll;
using namespace std;
struct node
{
int v,next;
} rea[maxn<<1];
int head[maxn],dis[maxn],len;
void inct()
{
me(head,-1);len=0;
}
void add(int u,int v)
{
rea[len].v=v;
rea[len].next=head[u];
head[u]=len++;
}
void dfs(int u)
{
for(int i=head[u];i!=-1;i=rea[i].next)
{
int v=rea[i].v;
if(dis[v]==-1)
{
dis[v]=dis[u]+1;
dfs(v);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
inct();
int n,q;
scanf("%d%d",&n,&q);
for(int i=1; i<n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
me(dis,-1);
int u=0,t_ma=-1;
dis[1]=0;//两次dfs求树的直径
dfs(1);
for(int i=1;i<=n;i++)
if(dis[i]>t_ma)
t_ma=dis[i],u=i;
me(dis,-1);t_ma=0,dis[u]=0;
dfs(u);
for(int i=1;i<=n;i++)
t_ma=max(t_ma,dis[i]);
t_ma++;//因为我们算的是树的直径,直径上的节点数等于直径长度+1.
while(q--)
{
int k;
scanf("%d",&k);
if(k<=t_ma)
printf("%d\n",k-1);
else
printf("%d\n",t_ma-1+(k-t_ma)*2);
}
}
return 0;
}