牛客网 长安大学第三届ACM-ICPC程序设计竞赛(同步赛)G Go For Travel[dfs+想法]

题意:给你一棵树,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));
		}
	}
} 


猜你喜欢

转载自blog.csdn.net/acterminate/article/details/80037208