题目:CH6201.
题目大意:给定一棵
n
n
n个点的树,让你扩充成一张完全图,使得原树是这张完全图的唯一最小生成树,并输出加的边的最小边权和.
1
≤
n
≤
6000
1\leq n\leq 6000
1≤n≤6000,边权
≤
100
\leq 100
≤100,数据组数
≤
10
\leq 10
≤10.
这道题用了一个类似于Kruskal的东西,然后顺便计算出了最小边权和.
首先,我们将树拆开,将边排序,然后不断用并查集合并.
每合并一次,我们设合并的两个联通块为 x x x和 y y y,那么合并时就会 x x x和 y y y之间除了已有的这条边本身,其它边的边权都要大于已有的这条边.
而且我们可以发现,其它边的限制条件肯定只有大于这条边和比这条边小的树边,所以我们发现其它边的边权只要设成这条边的边权 + 1 +1 +1即可.
那么我们就kruskal的同时,每当加入一条边,就将答案加上其它的边的边权,我们发现其它边的数量即为
x
x
x的大小乘上
y
y
y的大小减
1
1
1,边权都为这条边的边权加
1
1
1.写成公式即为:
a
n
s
=
a
n
s
+
(
x
.
s
i
z
e
∗
y
.
s
i
z
e
−
1
)
∗
(
v
[
i
]
+
1
)
.
ans=ans+(x.size*y.size-1)*(v[i]+1).
ans=ans+(x.size∗y.size−1)∗(v[i]+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;
}