【GMOJ4279】树上路径

题目

题目链接:https://gmoj.net/senior/#main/show/4279
有一棵 \(n\) 个点的无向树,每个点的编号在 \(1\sim n\) 之间,求出每个点所在的最长路。

思路

先用 dp 求出每个点到其子树内路径长度最大值和其子树内最长路。
然后再次搜索每一个点,同时枚举其兄弟节点更新从子树外部连接到这一个点的最长路径。更新答案即可。
时间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=100010;
int n,tot,f[N],head[N],maxl[N];

struct edge
{
	int next,to,dis;
}e[N*2];

void add(int from,int to,int dis)
{
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].next=head[from];
	head[from]=tot;
}

void dfs1(int x,int fa)
{
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa)
		{
			dfs1(v,x);
			maxl[x]=max(maxl[x],f[x]+f[v]+e[i].dis);
			f[x]=max(f[x],f[v]+e[i].dis);
		}
	}
}

void dfs2(int x,int fa,int dis)
{
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to,maxd=dis;
		if (v!=fa)
		{
			for (int j=head[x];~j;j=e[j].next)
				if (e[j].to!=fa && e[j].to!=v)
					maxd=max(maxd,f[e[j].to]+e[j].dis);
			maxl[v]=max(maxl[v],maxd+e[i].dis+f[v]);
			dfs2(v,x,maxd+e[i].dis);
		}
	}
}

int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	memset(head,-1,sizeof(head));
	scanf("%d",&n);
	for (int i=1,x,y,z;i<n;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z); add(y,x,z);
	}
	dfs1(1,0); dfs2(1,0,0);
	for (int i=1;i<=n;i++)
		printf("%d\n",maxl[i]);
	return 0;
}
posted @ 2020-10-23 15:16  stoorz  阅读(73)  评论(0编辑  收藏  举报