重点 费用等于道路长度乘以道路两端的国家个数之差的绝对值。
例如,在下图中,虚线所示道路两端分别有 2 个、4 个国家,如果该道路长度为1,则费用为1×|2-4|=1x2=2。图中圆圈里的数字表示国家的编号。
要注意的是 求的是道路两边的国家个数之差绝对值,我以为是kruskal做呢。。。哼哧哼哧求连通块半天,百思不得其解绝对值为0的情况怎么处理。
如何求道路两端的国家数
设两端分别为a,b son数组记录以a为根的子树节点数量 另一端的节点数量就为n-son[a]
所以每一条边的花费就为
∣
s
o
n
[
a
]
−
(
n
−
s
o
n
[
a
]
)
∣
×
w
[
i
]
=
∣
n
−
2
×
s
o
n
[
a
]
∣
×
w
[
i
]
|son[a]-(n-son[a])|\times w[i]=|n-2\times son[a]|\times w[i]
∣son[a]−(n−son[a])∣×w[i]=∣n−2×son[a]∣×w[i]
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
typedef long long ll;
typedef vector<int> v;
const int N = 2e6+10;
int ne[N],h[N],w[N],e[N],idx,n;
int son[N];//记录点以a为子树的节点数
ll ans;
void add(int a, int b, int c) // 添加一条边a->b,边权为c
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs(int u,int fa){
son[u]=1;//一开始只有1
for (int i=h[u];~i;i=ne[i]){
int j=e[i];
if (j!=fa){//双向边 容易绕回来 需要特判掉
dfs(j,u);
ans+=(ll)abs(n-2*son[j])*w[i];//注意会爆int 推导见上方
son[u]+=son[j];//u是j的父节点
}
}
}
int main(){
scanf ("%d",&n);
memset(h, -1, sizeof h);
for (int i=0;i<n-1;i++){
int a,b,c;
scanf ("%d%d%d",&a,&b,&c);
add(a, b, c),add(b,a,c);
}
dfs(1,1);
cout<<ans;
return 0;
}