题目链接
abc214 D - Sum of Maximum Weights
rating : 1341
题目描述
We have a tree with N N N vertices numbered 1 , 2 , … , N 1,2,…,N 1,2,…,N.
The i-th edge ( 1 ≤ i ≤ N − 1 1≤i≤N−1 1≤i≤N−1) connects Vertex u i u_i ui and Vertex v i v_i vi and has a weight w i w_i wi .
For different vertices u u u and v v v, let f ( u , v ) f(u,v) f(u,v) be the greatest weight of an edge contained in the shortest path from Vertex u u u to Vertex v v v.
Find ∑ i = 1 N − 1 ∑ j = i + 1 N f ( i , j ) \sum_{i = 1}^{N - 1}\sum_{j = i + 1}^{N} f(i,j) ∑i=1N−1∑j=i+1Nf(i,j)
Constraints
-
2 ≤ N ≤ 1 0 5 2≤N≤10^5 2≤N≤105
-
1 ≤ u i , v i ≤ N 1≤u_i ,v_i ≤N 1≤ui,vi≤N
-
1 ≤ w i ≤ 1 0 7 1≤w_i ≤10^7 1≤wi≤107
-
The given graph is a tree.
-
All values in input are integers.
Input
Input is given from Standard Input in the following format:
N
u1 v1 w1
⋮
uN−1 vN−1 wN−1
Output
Print the answer.
Sample Input 1
3
1 2 10
2 3 20
Sample Output 1
50
We have f ( 1 , 2 ) = 10 f(1,2)=10 f(1,2)=10, f ( 2 , 3 ) = 20 f(2,3)=20 f(2,3)=20, and f ( 1 , 3 ) = 20 f(1,3)=20 f(1,3)=20, so we should print their sum, or 50 50 50.
Sample Input 2
5
1 2 1
2 3 2
4 2 5
3 5 14
Sample Output 2
76
解法:并查集
题目的大致意思是:给你一颗树,树中每两个相邻节点 u u u 和 v v v 之间的权重是 w w w,并且定义了一种操作 f ( i , j ) f(i,j) f(i,j) 表示节点 i i i 到 节点 j j j 的最短路径上的最大的那个权重值。
我们要做的就是求出所有这样的 f ( i , j ) f(i,j) f(i,j) 的总和。
对于本题,我们使用并查集求解。
我们首先对输入 { u , v , w } \{u,v,w\} {u,v,w} 按照权重 w w w 从小到大的排序。
我们从小的权重值 w w w 开始枚举,计算以 w w w 为最大权重值的路径的条数 t t t。这个条数 t = t = t= u u u 所在的连通块元素个数 × \times × v v v 所在的连通块元素个数。
我们用一个 s z sz sz 数组来记录每个连通块的元素个数。
对于 u u u 和 v v v,他们的父节点分别是 f i n d ( u ) , f i n d ( v ) find(u) , find(v) find(u),find(v),我们令其为 x , y x,y x,y。
-
如果此时 x = y x = y x=y,说明 u u u 和 v v v 此时就已经在同一个连通块内了,我们就不用计算了。
-
如果此时 x ≠ y x \neq y x=y,那么我们就要将 x x x 和 y y y 这两个连通块 通过 { u , v , w } \{ u,v,w\} {u,v,w} 这条边连接起来。那么此时 t = s z [ x ] × s z [ y ] t = sz[x] \times sz[y] t=sz[x]×sz[y],所以这条边的贡献就为 t × w = s z [ x ] × s z [ y ] × w t \times w = sz[x] \times sz[y] \times w t×w=sz[x]×sz[y]×w。接着合并这两个连通块, f [ x ] = y , s z [ y ] = s z [ y ] + s z [ x ] f[x] = y , sz[y] =sz[y] + sz[x] f[x]=y,sz[y]=sz[y]+sz[x],这一步操作相当于将 x x x 所代表的连通块作为一个新节点插入到了 以 y y y 代表的连通块中。
时间复杂度: O ( n × l o g n ) O(n \times logn) O(n×logn)
C++代码:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
using LL = long long;
const int N = 1e5 + 10;
int f[N],sz[N];
int n;
int find(int x){
if(f[x] != x) {
return f[x] = find(f[x]);
}
else return x;
}
void merge(int x,int y){
int px = find(x) , py = find(y);
if(px == py) return;
f[px] = py;
sz[py] += sz[px];
}
void solve(){
cin>>n;
for(int i = 0;i < n;i++) {
f[i] = i;
sz[i] = 1;
}
vector<tuple<int,int,int>> a;
for(int i = 0;i < n - 1;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
--u , --v;
a.emplace_back(w,u,v);
}
sort(a.begin(),a.end());
LL ans = 0;
for(auto &[w,u,v]:a){
int x = find(u) , y = find(v);
ans += w * 1LL * sz[x] * sz[y]; //将乘积转成 long long 防止溢出
merge(u,v);
}
cout<<ans<<'\n';
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","rt",stdin);
freopen("out.txt","wt",stdout);
#endif
int t = 1;
//cin>>t;
while(t--){
solve();
}
return 0;
}