题意:给你一棵树,q个询问,每个询问求从v出发,总步数小于等于k的时候的能走到的最多的点(每个点只算一次)。
题解:可以确定的是走过的路径肯定是一条路径上的边只走过一次+其他走过边都经过两次的情况,所以我们只需要找到距离当前点最远的点,他们之间只走过一次,其他边都计算为两次即可,找树的直径的两端点可以直接找到最远的点在哪里。
AC代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#define N 100005
using namespace std;
vector<int>vt[N];
int dis1[N],dis2[N];
void dfs(int u,int fa)
{
for(int i=0;i<vt[u].size();i++)
{
int to=vt[u][i];
if(to==fa)continue;
dis1[to]=dis1[u]+1;
dfs(to,u);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)dis1[i]=dis2[i]=0,vt[i].clear();
for(int i=0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
vt[u].push_back(v);
vt[v].push_back(u);
}
dfs(1,1);
int s1,s2,ma=-1;
for(int i=1;i<=n;i++)
if(ma<dis1[i])
ma=dis1[i],s1=i;
for(int i=1;i<=n;i++)dis1[i]=0;
dfs(s1,s1);
ma=-1;
for(int i=1;i<=n;i++)
if(ma<dis1[i])
ma=dis1[i],s2=i;
for(int i=1;i<=n;i++)dis2[i]=dis1[i],dis1[i]=0;
dfs(s2,s2);
int q;
scanf("%d",&q);
while(q--)
{
int u,k;
scanf("%d%d",&u,&k);
int dist=max(dis1[u],dis2[u]);
if(dist>=k)printf("%d\n",k+1);
else printf("%d\n",min(n,dist+(k-dist)/2+1));
}
}
}