CF1294F Three Paths on a Tree

CF1294F Three Paths on a Tree

洛谷传送门

题意翻译

给定一棵含 n\ (3\leq n\leq2\cdot 10^5)n (3≤n≤2⋅105) 个结点的无权树,试找出三个结点 uu、vv、ww,\operatorname{s.t.}s.t.

\operatorname{card}({u,v\text{ 间的路径}}\cup{v,w\text{ 间的路径}}\cup{w,u\text{ 间的路径}})card({u,v 间的路径}∪{v,w 间的路径}∪{w,u 间的路径})

最大。

你需要输出两行:

第一行为 \max\operatorname{card}({u,v\text{ 间的路径}}\cup{v,w\text{ 间的路径}}\cup{w,u\text{ 间的路径}})maxcard({u,v 间的路径}∪{v,w 间的路径}∪{w,u 间的路径})

第二行三个整数,即 uu、vv、ww,如有多种答案,输出一种即可。


题解:

贪心+树。

首先简单想一想能发现:答案应该是树的直径加上所有不在直径上的节点中,距离直径最长的距离。

那么只需要模拟这个过程就可以:

先两次DFS求出树的直径(记录路径长和两个端点),然后把直径上所有节点打上标记,然后枚举所有非直径上的节点,更新最大距离,就可以过了。

复杂度是\(O(n)\)级别。

代码:

#include<cstdio>
using namespace std;
const int maxn=2e5+5;
int n;
int tot,head[maxn],nxt[maxn<<1],to[maxn<<1];
int maxx,pos[4],ans;
int deep[maxn],fa[maxn];
bool v[maxn];
void add(int x,int y)
{
	to[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
void dfs(int x,int f,int p)
{
	if(p==2)
		fa[x]=f;
	deep[x]=deep[f]+1;
	if(deep[x]>maxx)
	{
		maxx=deep[x];
		pos[p]=x;
	}
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i];
		if(y==f)
			continue;
		dfs(y,x,p);
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	deep[0]=-1;
	dfs(1,0,1);
	maxx=0;
	dfs(pos[1],0,2);
	int x=pos[2];
	while(x)
	{
		v[x]=1;
		x=fa[x];
	}
	ans+=maxx;
	maxx=0;
	int tmp=0;
	for(int i=1;i<=n;i++)
	{
		if(v[i])
			continue;
		else
		{
			x=i;
			tmp=0;
			while(!v[x])
			{
				x=fa[x];
				tmp++;
			}
			if(maxx<tmp)
			{
				maxx=tmp;
				pos[3]=i;
			}
		}
	}
	if(!maxx)
		for(int i=1;i<=n;i++)
			if(v[i]&&i!=pos[1]&&i!=pos[2])
			{
				pos[3]=i;
				break;
			}
	ans+=maxx;
	printf("%d\n%d %d %d\n",ans,pos[1],pos[2],pos[3]);
	return 0;
}
posted @ 2020-12-04 15:16  Seaway-Fu  阅读(153)  评论(0编辑  收藏  举报