第二遍做这一题了,很经典,附上一张盗来的图,
思路
- 首先用一个 dfs 去预处理每个节点 x,到以 x 为根的子树的叶子节点的最大、最小值,就是求树的直径的时候的那个 dp 求法,并且标记最大最小值的分别经过的事 x 的那个子节点,
- 然后再用另一个 DFS 函数去以当前点 x 为起点所能走的最长路径,如下图,如果 x=2 的时候我们可在这个树分成两部分,第一部分是以 x 为子树的那一部分,即蓝色圈着的部分,另一部分是剩余的部分,即红色线圈着的部分。
- 这两部分都有可能产生最大值,蓝色部分产色的最大值,可以通过 与处理的数据直接求的,而红色部分则可以通过,从上往下的递归过程维护得到,
- 从红、蓝两部分的最大值中选择一个最大值就是 x 节点的答案。
题解
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <queue>
#include <map>
#include <bitset>
#include <vector>
using namespace std;
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
void Run(int x = 0) {
#ifdef ACM //宏定义免注释 freopen
if (! x) fre(); else Fre();
#endif
}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define db double
#define ll long long
#define ull unsigned long long
#define Pir pair<ll, ll>
#define m_p make_pair
#define for_(i, s, e) for(ll i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(ll i = (ll)(e); i >= (ll)(s); i --)
#define memset(a, b, c) memset(a, (int)b, c);
#define size() size() * 1LL
#define sc scanf
#define pr printf
#define sd(a) sc("%lld", &a)
#define ss(a) sc("%s", a)
#define __ pr( "------------------------\n" );
#define ___ pr("\n------------------------\n");
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define esp 1e-7
#define mod (ll)(1e9 + 7)
/*=========================ACMer===========================*/
const ll mxn = 1e4 + 10;
struct Edge
{
ll v, w, next;
} edge[mxn << 1];
ll head[mxn], tot;
Pir f[mxn][2];
void Add(ll u, ll v, ll w)
{
edge[++ tot] = (Edge){ v, w, head[u] };
head[u] = tot;
}
void pre_dfs(ll u, ll p)
{
for (ll i = head[u]; i; i = edge[i].next)
{
ll v = edge[i].v, w = edge[i].w;
if(v == p) continue;
pre_dfs(v, u);
ll tmp = f[v][0].fi + w;
if(tmp >= f[u][0].fi) f[u][1] = f[u][0], f[u][0] = m_p(tmp, v);
else if(tmp > f[u][1].fi) f[u][1] = m_p(tmp, v);
}
}
ll dp[mxn];
void dfs(ll u, ll p, ll pmx)
{
for (ll i = head[u]; i; i = edge[i].next)
{
ll v = edge[i].v, w = edge[i].w;
if(v == p) continue;
ll fa_mx = 0;
if(f[u][0].se != v) fa_mx = f[u][0].fi;
else if(f[u][1].se != v) fa_mx = f[u][1].fi;
ll now_mx = max(fa_mx, pmx) + w;
dp[v] = max(f[v][0].fi, now_mx);
dfs(v, u, now_mx);
}
}
void init(ll n)
{
memset(f, 0, sizeof f);
memset(head, 0, sizeof head);
tot = 0;
}
int main()
{
Run();
ll n;
while (sd(n) != EOF)
{
init(n);
ll x, y;
for_(i, 2, n)
{
sc("%lld %lld", &x, &y);
Add(i, x, y);
Add(x, i, y);
}
pre_dfs(1, 0);
dfs(1, 0, 0);
dp[1] = max(f[1][0].fi, f[1][1].fi); //单独计算一下 1 根节点
for_(i, 1, n) pr("%lld\n", dp[i]);
}
return 0;
}