题解:P10962 Computer

· · 题解

题目传送门

题意

给定一棵有 n 个节点的树,对于每个节点,都求出离他最远的节点离他的距离。

思路

ACcode:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e4 + 5;
vector<pair<int, int> > g[N];
int dis1[N], dis2[N]; //dis1表示子树的最长路, dis2表示子树的次长路 
int f[N], son[N]; //son表示子树的最长路的节点编号, f表示子树外的最长路 
int n;
void dfs1(int u, int fa)
{
    for (auto x : g[u])
    {
        int v = x.first, w = x.second;
        if (v == fa)
            continue;
        dfs1(v, u);
        //回溯过程将子树的信息带回来更新u
        if (dis1[u] < dis1[v] + w)
        {
            dis2[u] = dis1[u]; //先更新次长路
            dis1[u] = dis1[v] + w;
            son[u] = v; // 最长路先经过v
        }
        else if (dis2[u] < dis1[v] + w)
            dis2[u] = dis1[v] + w; 
    }
    return ;
}
void dfs2(int u, int fa)
{
    for (auto x : g[u])
    {
        int v = x.first, w = x.second;
        if (v == fa)
            continue;
        //在递的过程中更新数据,父亲更新儿子
        if (son[u] != v) //u的最长路不包含v, 可以直接用 
            f[v] = max(dis1[u], f[u]) + w;
        else
            f[v] = max(dis2[u], f[u]) + w;
        dfs2(v, u);
    }
    return ;
}
void solve()
{
    for (int i = 1; i <= n; i++)
        g[i].clear();
    //多测注意清空 
    memset(dis1, 0, sizeof dis1);
    memset(dis2, 0, sizeof dis2);
    memset(f, 0, sizeof f);
    for (int i = 2; i <= n; i++) 
    {
        int u, v;
        cin >> u >> v;
        g[i].push_back({u, v});
        g[u].push_back({i, v});
    }
    dfs1(1, 0); //从下往上dfs
    dfs2(1, 0); //从上往下dfs
    for (int i = 1; i <= n; i++)
        cout << max(dis1[i], f[i]) << "\n";
    return ;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    while (cin >> n)
        solve();
    return 0;
}