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)\),