版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83108132
题目:CH6201.
题目大意:给定一棵树,让你扩充成一张完全图,使得原树是这张完全图的唯一最小生成树,并输出加的边的最小边权和.
这道题用了一个类似于Kruskal的东西,然后顺便计算出了最小边权和.
首先,我们将树拆开,将边排序,然后不断用并查集合并.
每合并一次,我们设合并的两个联通块为x和y,那么合并时就会x和y之间除了已有的这条边本身,其它边的边权都要大于已有的这条边.
而且我们可以发现,其它边的限制条件肯定只有大于这条边和比这条边小的树边,所以我们发现其它边的边权只要设成这条边的边权+1即可.
那么我们就kruskal的同时,每当加入一条边,就将答案加上其它的边的边权,我们发现其它边的数量即为x的大小乘上y的大小减1,边权都为这条边的边权加1.写成公式即为:
.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=6000;
struct side{
int x,y,v;
bool operator < (const side p)const{return v<p.v;}
}e[N+9];
int ans,n;
int fa[N+9],cnt[N+9];
int get(int u){return fa[u]=u^fa[u]?get(fa[u]):u;}
Abigail into(){
scanf("%d",&n);
for (int i=1;i<n;i++)
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);
}
Abigail work(){
ans=0;
for (int i=1;i<=n;i++) fa[i]=i,cnt[i]=1;
stable_sort(e+1,e+n);
for (int i=1;i<n;i++){
ans+=(e[i].v+1)*(cnt[get(e[i].x)]*cnt[get(e[i].y)]-1);
cnt[get(e[i].x)]+=cnt[get(e[i].y)];
fa[get(e[i].y)]=get(e[i].x);
}
}
Abigail outo(){
printf("%d\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while (T--){
into();
work();
outo();
}
return 0;
}