ABC222 F - Expensive Expense(树的直径)

目录

Description

有一棵树,求每一个节点到其他节点的最短路径的最大值,\(dis(i,j)\),定义为 \(i\) 节点至 \(j\) 节点的边权之和以及终点 \(j\) 的点权

State

\(1<=n<=2*10^5\)

\(1<=a_i<=n\)

\(1<=b_i<=n\)

\(1<=c_i<=10^9\)

\(1<=d_i<=10^9\)

Input

6
1 2 3
1 3 1
1 4 4
1 5 1
1 6 5
9 2 6 5 3 100

Output

105
108
106
109
106
14

Solution

小技巧:如果将点权转化成边权,每一个节点将不会再有点权,即添加边 \((i, i+n)\)

在树中,如果求一个点 \(i\) 的最长路径,一定是点 \(i\) 到达该树直径的两个端点的其中一个


现在我们需要知道的是任意一个点到达这两个端点的距离,答案即为 \(max(a[i], b[i])\)


$hint: $ 如果该点处于端点位置,那么该点的答案一定是到达另一个端点的距离,因为题目不考虑起点的点权


Code

const int N = 4e5 + 5;
 
    int n, m, k, _;
    vector<pii> G[N];
    ll a[N];
    ll b[N];
    struct Node
    {
        int u, v, w;
        void read(){ sddd(u, v, w); }
    }t[N];
    
void add(int u, int v, int w)
{
    G[u].pb(mp(v, w));
    G[v].pb(mp(u, w));
}

void dfs(int u, int fa, ll *d, ll w)
{
    d[u] = d[fa] + w;
    int sz = G[u].size();
    for(int i = 0; i < sz; i ++){
        int v = G[u][i].fi;
        int w = G[u][i].se;
        if(v == fa) continue;
        dfs(v, u, d, w);
    }
}

signed main()
{
    // IOS;
    while(~ sd(n)){
        rep(i, 1, n - 1){
            t[i].read();
            add(t[i].u, t[i].v, t[i].w);
        }
        rep(i, 1, n){
            int x = read();
            t[i + n - 1] = {i, i + n, x};
            add(t[i + n - 1].u, t[i + n - 1].v, t[i + n - 1].w);
        }
        m = n + n;
        dfs(1, 0, a, 0);
        int p = max_element(a + 1, a + 1 + m) - a;
        dfs(p, 0, a, 0);
        int q = max_element(a + 1, a + 1 + m) - a;
        dfs(q, 0, b, 0);
        for(int i = 1; i <= n; i ++){
            if(i == p - n) pll(b[i]);
            else if(i == q - n) pll(a[i]);
            else pll(max(a[i], b[i]));
        }
    }
    // PAUSE;
    return 0;
}
posted @ 2021-10-19 09:23  Bcoi  阅读(91)  评论(0)    收藏  举报