hdu 2196求树上每个点各自的最远距离(树形dp)

题目链接

  • 记 f[u] 为节点 u 第一步向儿子方向走的最远距离
  • 记 g[u] 为节点 u 第一步向父亲方向走的最远距离
  • 记 fa[u] 为节点 u 的父亲节点的编号
  • f[u] = max{f[v] + w(u, v)} ,v是u的儿子
  • g[u] = w(u, fa[u]) + max{g[p[u]], f[v] + w(fa[u], v)}, v 是 u 的兄弟
  • 所以要做两边dfs,先求出f再求出g。
  • 最后节点 u 的最远距离即为max{f[u], g[u]}。
#include <bits/stdc++.h>

using namespace std;

const int maxn = (int)1e4+100;
int n, f[maxn], g[maxn], fa[maxn];
vector< pair<int, int> > G[maxn];

void init(int n) {
    memset(f, 0, sizeof(f));
    memset(g, 0, sizeof(g));
    memset(fa, 0, sizeof(fa));
    for (int i = 1; i <= n; ++i) G[i].clear();  //!!
}
void dfs(int x, int par) {
    fa[x] = par;
    for (pair<int, int> pii : G[x]) {
        int to = pii.first;
        if (to == par) continue;
        dfs(to, x);
        f[x] = max(f[x], f[to] + pii.second);
    }
}
void dfs2(int x, int par) {
    int temp = 0;
    g[x] = g[par];
    for (pair<int, int> pii : G[par]) {
        int to = pii.first;
        if (to == fa[par]) continue;
        if (to == x) temp = pii.second;
        else {
            g[x] = max(g[x], f[to] + pii.second);
        }
    }
    g[x] += temp;
    for (pair<int, int> pii : G[x]) {
        int to = pii.first;
        if (to == par) continue;
        dfs2(to, x);
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    while (cin >> n) {
        init(n);
        for (int i = 2; i <= n; ++i) {
            int u, val;
            cin >> u >> val;
            G[i].emplace_back(make_pair(u, val));
            G[u].emplace_back(make_pair(i, val));
        }
        dfs(1, 0);
        dfs2(1, 0);
        for (int i = 1; i <= n; ++i) {
            cout << max(f[i], g[i]) << '\n';
        }
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值