题意:给定一棵N个节点的无根树,每条边都有一个权值V,选取其中一个点作为关键点,你可以任意增加某条边的权值,求使得从关键点出发,到任意一个叶子节点的距离都相同所需要增加的权值和。
数据范围:
对于40%的数据,N ≤ 1000
对于100%的数据,N ≤ 500000,V ≤ 1000000
-------------------------------------分割线------------------------------------
题解:一道比较显然的树形DP,不难想到我们把其他的链都向最长链看齐。
扫描一遍树,自底向上处理出当前节点的出边数量num,以及当前节点到叶节点的距离和sum。
算出最远的距离激发器的叶子节点距离maxn[x],然后对于其他叶子节点,所需要增加的长度显然即为 maxn[x] * num - sum。
累加答案即可。
#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
typedef pair<int, int> pii;
typedef double db;
const int N = 1e6 + 50;
int n, a[N], root;
int head[N], cnt = 0;
ll maxn[N], f[N];
struct node{ ll to, next, v; } e[N];
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar();}
while(ch >='0' && ch <='9') { x = (x<<3)+(x<<1)+(ch^48); ch = getchar();}
return x*f;
}
void add(int x, int y, int z){
e[++cnt].to = y; e[cnt].v = z;
e[cnt].next = head[x]; head[x] = cnt;
}
void init(){
n = read(); root = read();
rep(i, 1, n-1) {
int xx, yy, zz;
xx = read(); yy = read(); zz = read();
add(xx, yy, zz);
add(yy, xx, zz);
}
}
void dfs(int x, int fa){
f[x] = 0, maxn[x] = 0;
ll sum = 0, num = 0;
for(int i = head[x]; i; i = e[i].next){
int y = e[i].to;
if(y == fa) continue;
dfs(y, x); num ++;
f[x] += f[y];
maxn[x] = max(maxn[y] + e[i].v, maxn[x]);
sum += (ll)maxn[y] + e[i].v;
}
f[x] += (ll)maxn[x] * num - sum;
}
void work(){
dfs(root, 0);
printf("%lld
", f[root]);
}
int main(){
init();
work();
return 0;
}