AcWing 325. 计算机

传送门

题目大意:

一棵无根树,每条边有一个距离,求每个顶点到距离其最远的顶点的距离。

思路:

考虑树形DP+换根。

令D[x]x到以x为根的子树当中的最长距离,d[x]为次长距离,U[x]为x向上走的最长距离,F[x]为x的答案。

第一次dfs以1为根可以很容易求出D[x]与d[x]。

之后第二次dfs对每个顶点去求最终的答案。

令p为父节点,v为当前节点,l为p到v的距离,于是有

F[x]=max(D[x],U[x])

对于D[p] == D[v] + l的情况,说明p向下的最长距离可以从v经过,那么就应该从父节点的向下次长距离,向上的最长距离的最大值+p到v之间的距离中选择一个作为U[x],即U[x]=max(d[p],U[p])+l。

否则,直接就可以考虑父节点向下走的最大值,于是U[x]=max(D[p],U[p])+l

最后每个节点的答案即为F[x]。

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long LL;
//#define int LL
#pragma warning(disable :4996)
typedef unsigned long long ULL;
typedef pair<int, int> PII;
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const int maxn = 10010;
const long double eps = 1e-8;
const LL MOD = 998244353;

struct Edge {
	int to, len;
};
int N;
int root = 1;
int F[maxn], D[maxn], d[maxn], U[maxn];//D[x]x到以x为根的子树当中的最长距离,d[x]次长距离,U[x]x向上走的最长距离,F[x]x的答案。
vector<Edge>G[maxn];
bool used[maxn];

void add_edge(int from, int to, int len)
{
	G[from].push_back(Edge{ to,len });
	G[to].push_back(Edge{ from,len });
}

void dfs1(int v)
{
	d[v] = D[v] = 0;
	used[v] = true;
	for (int i = 0; i < G[v].size(); i++)
	{
		Edge& e = G[v][i];
		if (!used[e.to])
		{
			dfs1(e.to);
			int val = D[e.to] + e.len;
			if (val >= D[v])
			{
				d[v] = D[v];
				D[v] = val;
			}
			else if (val > d[v])
				d[v] = val;
		}
	}
}

void dfs2(int v, int p, int l)
{
	used[v] = true;
	if (D[p] == D[v] + l)//p的最长经过v
		U[v] = l + max(d[p], U[p]);
	else
		U[v] = l + max(D[p], U[p]);
	F[v] = max(U[v], D[v]);
	for (int i = 0; i < G[v].size(); i++)
	{
		Edge& e = G[v][i];
		if (!used[e.to])
			dfs2(e.to, v, e.len);
	}
}

void solve()
{
	memset(used, 0, sizeof(used));
	memset(D, 0, sizeof(D));
	memset(d, 0, sizeof(d));
	memset(F, 0, sizeof(F));
	memset(U, 0, sizeof(U));
	dfs1(root);
	memset(used, 0, sizeof(used));
	dfs2(root, 0, 0);
	for (int i = 1; i <= N; i++)
		cout << F[i] << endl;
}

int main()
{
	IOS;
	while (cin >> N)
	{
		for (int i = 0; i <= N; i++)
			G[i].clear();
		int v, len;
		for (int i = 2; i <= N; i++)
		{
			cin >> v >> len;
			add_edge(i, v, len);
		}
		solve();
	}

	return 0;
}

本文作者:Prgl

本文链接:https://www.cnblogs.com/Prgl/p/15956884.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Prgl  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开