qzezoj 1640 走廊泼水节
题面传送门
题目大意:构造一个完全图,使得在最小生成树唯一(题目中给出)的情况下权值总和最小。
直接克鲁斯卡尔模拟,在合并两棵树时进行操作。
合并两棵树时要连的边的条数是\(siz_x\times siz_y-1\),即将合并的这条边一定是两棵树中最大的边,而所有不在最小生成树内的边一定大于这条边,所以合并时\(ans+(siz_x\times siz_y-1)(w+1)\)
时间复杂度\(O(tnlogn)\)
代码实现:
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,k,x,y,t,z,un,wn,f[100039];
long long ans,siz[100039];
inline int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
struct yyy {int x,y,z;} s[200039];
inline bool cmp(yyy x,yyy y) {return x.z<y.z;}
int main() {
register int i;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
for(i=1; i<=n; i++) f[i]=i,siz[i]=1;
ans=0;
for(i=1; i<n; i++) scanf("%d%d%d",&x,&y,&z),s[i]=(yyy) {y,x,z};
sort(s+1,s+n,cmp);
for(i=1; i<n; i++) {
un=find(s[i].x);wn=find(s[i].y);
ans+=(siz[un]*siz[wn]-1)*(s[i].z+1);
//printf("%lld\n",ans);
siz[wn]+=siz[un];
f[un]=wn;
}
printf("%lld\n",ans);
}
}