b_lg_时态同步(后序遍历统计每棵子树的最大高度)

题目大意:有一个激发器,与若干个元件与之相连,它们组成一棵树,叶结点可能不在同一水平线上,你可以花费1代价使得一条导线增加电流的一个单位的传输时间,问至少要使用多少道具才能让叶结点处于统一水平面上。
输入:n 行 a,b,t。表示该条导线连接节点a与节点b,且激励电流通过这条导线需要t个单位时间。

方法一:

比较容易想到的是:先移动靠近根节点的结点(假设为u)会最小化开销(ps:牵一发而动u的子树全身)

后序遍历从低到高枚举并统计每一刻子树的高度,比如现有根节点 u,有 u 的两个子节点 s1、s2,u到s1的距离为3,u到s2的距离为1,d[u]=max(d[s1], d[2])=3,需要花费的道具数就是:\(\sum_{1}^{size(tree_u)}(d[u]-(d[s_i]+w_{u->s_i})\)的总和,即根节点的最大高度 -(直接子节点的最小高度+根到直接子节点的边权)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
struct node {
    ll u,w;
};  
vector<node> g[N];
ll ans, d[N], vis[N];

void dfs(int u, int fa) {
    for (auto& to : g[u]) {
        int v=to.u, w=to.w;
        if (v!=fa) {
            dfs(v,u);
            d[u]=max(d[u], d[v]+w);
        }
    }
    for (auto& to : g[u]) {
        int v=to.u, w=to.w;
        if (v!=fa) {
            ans+=d[u]-(d[v]+w);
        }
    }
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n,s,u,v,w; cin>>n>>s;
    for (int i=1; i<n; i++) {
        cin>>u>>v>>w;
        g[u].push_back({v,w});
        g[v].push_back({u,w});
    }
    dfs(s,-1);
    cout<<ans;
    return 0;
}

复杂度分析

  • Time\(O(v+e)\)
  • Space\(O(v+e)\)
posted @ 2020-09-14 20:22  童年の波鞋  阅读(116)  评论(0编辑  收藏  举报