1. 程式人生 > 實用技巧 >CF1294F Three Paths on a Tree

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;
}