1. 程式人生 > >Computer HDU - 2196 (樹形dp)

Computer HDU - 2196 (樹形dp)

A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information. 



Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.

Input

Input file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.

Output

For each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).

Sample Input

5
1 1
2 1
3 1
1 1

Sample Output

3
2
3
4
4

題目大意:

讓你求每個節點到其他節點的最遠距離。

解題思路:

用樹形dp可以解決,不過貌似也有人用樹的直徑過了。。。

我們來講講如何dp,一個節點到其他節點的最長距離無非兩種情況:

          1.從該節點向下到達某個葉子節點。

          2.從該節點向上到達某個節點然後在向下到達某個葉子節點。

我們只需要求出這兩種情況,然後比較大小輸出大的就行了。

思路有了,我們來想一想如何求這兩種情況,用dp[u][0]代表從編號為u的節點向下到達某個葉子節點的最遠距離,那麼狀態轉移方程可表述為dp[u][0] = max(dp[vi][0] + wi)  (v代表u的兒子節點,w為二者之間所連邊的權值),這就是第一種情況。要求第二種情況,我們得維護一個次遠距離,dp[u][1]代表從編號為u的節點向下到達某個葉子節點的次遠距離。這樣的話,我們在求u節點的最遠距離的時候就可以利用u的父親節點維護的最遠距離和次遠距離來求解u節點的值,具體方法就是求出dp[i][0], dp[i][1]之後,在來一次dfs,採用從根向葉子節點的方式求出從每個節點向上所能到達的最遠距離,記為dp[i][2]。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>

using namespace std;

typedef long long ll;
const int maxn = 10100;

int n, be, en;

ll dist[maxn], dp[maxn][4], son[maxn];
vector < ll > gra[maxn], val[maxn];

void dfs1(int u, int father)       //用來求dp[i][0], dp[i][1];
{
	ll ans = 0;
	int id = -1;
	for(int i = 0; i < gra[u].size(); ++ i)
	{
		int v = gra[u][i];
		ll w = val[u][i];
		if(v != father)
		{
			dfs1(v, u);
			if(ans < dp[v][0] + w)
			{
				ans = dp[v][0] + w;
				id = v;      //要儲存下來,之後求dp[i][2]也要用;
			}
		}
	}
	for(int i = 0; i < gra[u].size(); ++ i)
	{
		int v = gra[u][i];
		ll w = val[u][i];
		if(v != father && v != id)
		{
			dp[u][1] = max(dp[u][1], dp[v][0] + w);
		}
	}
	dp[u][0] = ans;
	son[u] = id;
}

void dfs2(int u, int father)       //求dp[i][2]
{
	for(int i = 0; i < gra[u].size(); ++ i)
	{
		int v = gra[u][i];
		ll w = val[u][i];
		if(v != father)
		{
			if(son[u] == v)         //採用了從根向下更新的方式
			{
				dp[v][2] = max(dp[u][2], dp[u][1]) + w;   //如果v正好是最遠距離的經過的節點就和次遠距離dp[i][1]比較
			}
			else
			{
				dp[v][2] = max(dp[u][2], dp[u][0]) + w;   //否則就和最遠距離dp[i][0]比較
			}
			dfs2(v, u);        //所以先求值在向下遞迴
		}
	}
}

int main()
{
	//freopen("in.txt", "r", stdin);
	while(cin >> n)
	{
		ll v, w;
		memset(dp, 0, sizeof(dp));
		for(int i = 1; i <= n; ++ i)
			gra[i].clear(), val[i].clear();
		for(int i = 2; i <= n; ++ i)
		{
			scanf("%lld%lld", &v, &w);
			gra[i].push_back(v);
			gra[v].push_back(i);
			val[i].push_back(w);
			val[v].push_back(w);
		}
		dfs1(1, 0);
		dfs2(1, 0);
		for(int i = 1; i <= n; ++ i)
		{
			cout << max(dp[i][0], dp[i][2]) << endl;
		}
	}
	return 0;
}