Forsaken喜欢独一无二的树
题目描述
众所周知,最小生成树是指使图中所有节点连通且边权和最小时的边权子集。
不过最小生成树太简单了,我们现在来思考一个稍微复杂一点的问题。
现在给定一个n个点,m条边的图,每条边e_i 都有一个权值w_i 。定义删除一条边e_i 的代价为w_i,并且你可以对这个图执行任意次删边操作。
设这个图的最小生成树权值和为sum,定义一个图的最小生成树是独一无二的当且仅当这个图的边集中没有除最小生成树外的其他子集能满足权值和为sum且使得所有点连通。一个图刚开始可能没有独一无二的最小生成树,现在你可以删除一些边,使得剩下的边的最小生成树大小依然为sum并且这个图的最小生成树是独一无二的。
现在我们想要知道删除的边的权值和最小是多少?
输入描述:
第一行输入为nn和mm,表示这个图的点数和边数。
接下来mm行,每行三个值u_i,v_i ,w_i ,分别代表每条边的两个端点和边权。
输出描述:
一个整数,代表删除的边的最小权值和。
示例1
输入
1 0
输出
0
备注:
1≤n≤2e5
n−1≤m≤2e5
1≤u_i ,v_i ≤n
1≤w_i≤1e9
分析:
题目的意思即是说,删除一些边使最小生成树唯一,删除的边权值之和要最小。
Kruskal算法会把边的权值按从小到大排序,然后判断当前边的两个端点所在连通块是否连通。如果没有连通,那么这条边就是我们需要的。
对于多条能联通两个不同集合的边来说,权值大的我们不选入生成树,如果权值最小值唯一那就纳入生成树,现在就是要处理最小值不唯一的情况。
处理方法:
1.遍历这m条边{
2.从当前边往后遍历,把与当前边相同的都找到
3.遍历从当前边到与当前边权值相同的最后一条边:
判断是否属于同一集合,不同就加起来
4.由于第三步我们多加了,在这一步把多加的减掉,怎么减:只需要把权值相同的边减一条走即可
}
AC代码:
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,m,u,v,w;
const int N=200005;
int f[N];
struct node{
int st,en