计算机(换根dp)⭐

题面

一所学校前一段时间买了第一台计算机(所以这台计算机的ID是1)。

近年来,学校又购买了N-1台新计算机。

每台新计算机都与之前买进的计算机中的一台建立连接。

现在请你求出第i台计算机到距离其最远的计算机的电缆长度。

例如,上图中距离计算机1最远的是计算机4,因此 S1=3;距离计算机2最远的是计算机4和5,因此 S2=2;距离计算机3最远的是计算机5,所以 S3=3;同理,我们也得到 S4=4,S5=4。

输入格式

输入包含多测试数据。

每组测试数据第一行包含整数N。

接下来N-1行,每行包含两个整数,第 i 行的第一个整数表示第 i 台电脑买入时连接的电脑编号,第二个整数表示这次连接花费的电缆长度。

输出格式

每组测试数据输出N行。

第 i 行输出第 i 台电脑的 Si。

数据范围

1≤N≤10000,
电缆总长度不超过109

输入样例:

5
1 1
2 1
3 1
1 1

输出样例:

3
2
3
4
4

题解

标准的换根dp

首先想到对于定根为1 f[u] = max(f[u], f[son] + cost)

然后递归dfs, 就可以解出根为1的ans

怎么换根呢? 也是dfs, f[son] = max(f[son], f[u] + cost)

问题来了!

你怎么知道f[u]不是通过f[son]得到的呢?

这样不就套娃了? 根 根据儿子得到最大值, 儿子又通过根得到最大值

所以自然想到 设状态为 f[u][2]

f[u][0] = <根为u的最大值, 是通过儿子x得到的>

f[u][1] = <根为u的次大值, 是通过儿子y得到的> (y != x, f[u][1] <= f[u][0])

换根的时候判断一下是选 f[u][0] 还是 f[u][1] 转移就好了

至于复杂度, 两个dfs深度相同, 每个dfs每个节点就访问为一次

代码

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define fi first
#define se second
using namespace std;
typedef pair<int, int> PII;

const int maxn = 10005;

int n, ans[maxn];
int h[maxn], to[maxn], ne[maxn], co[maxn], tot;
PII f[maxn][2];

void add(int u, int v, int c)
{
    ne[++tot] = h[u]; h[u] = tot; co[tot] = c; to[tot] = v;
}

void dp(int u)
{
    for (int i = h[u]; i; i = ne[i])
    {
        int& v = to[i]; 
        dp(v);

        if (f[v][0].fi + co[i] > f[u][0].fi) 
            f[u][1] = f[u][0], f[u][0] = { f[v][0].fi + co[i], v };
        else if (f[v][0].fi + co[i] > f[u][1].fi)
            f[u][1] = { f[v][0].fi + co[i], v };
    }
}

void dfs(int u, int fa, int c)
{
    int cost = c + (f[fa][0].se == u ? f[fa][1].fi : f[fa][0].fi);
    if (cost > f[u][0].fi) f[u][0] = { cost, fa };
    else if (cost > f[u][1].fi) f[u][1] = { cost, fa };

    ans[u] = f[u][0].fi;

    for (int i = h[u]; i; i = ne[i]) dfs(to[i], u, co[i]);
}

int main()
{
    while (cin >> n)
    {
        memset(h, 0, sizeof h); tot = 0;
        memset(f, 0, sizeof f);

        for (int i = 2, u, c; i <= n; ++i)
        {
            cin >> u >> c;
            add(u, i, c);
        }

        dp(1);

        dfs(1, 0, 0);

        rep (i, 1, n) cout << ans[i] << '
';
    }
    return 0;
}
原文地址:https://www.cnblogs.com/2aptx4869/p/12879634.html