codevs 2796 最小完全图

orz CYZ。。。。

我们考虑模仿kruskal的建造过程:将边排序,考虑到这样一个性质:在一个建到一半的最小生成树中,两点直接连的边的距离一定严格大于它们在最小生成树上的路径边权最大值

(反之就不能连最小生成树的那条边),因此我们只要用一个并查集体现kruskal的过程,再维护每个子树的size,然后更新答案(边权+1)即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxe 30005
#define maxv 30005
using namespace std;
struct edge
{
long long u,v,w;
}e[maxe];
long long g[maxv],n,x,y,z,father[maxv],ans=0;
long long size[maxv];
bool cmp(edge x,edge y)
{
return x.w<y.w;
}
long long getfather(long long x)
{
if (x!=father[x])
father[x]=getfather(father[x]);
return father[x];
}
void unionn(long long x,long long y)
{
long long r1=getfather(x),r2=getfather(y);
if (r1!=r2)
{
father[r1]=r2;
size[r2]=size[r2]+size[r1];
}
}
int main()
{
memset(g,0,sizeof(g));
scanf("%lld",&n);
for (long long i=1;i<n;i++)
{
scanf("%lld%lld%lld",&e[i].u,&e[i].v,&e[i].w);
ans=ans+e[i].w;
father[i]=i;
size[i]=1;
}
father[n]=n;size[n]=1;
sort(e+1,e+n,cmp);
for (long long i=1;i<n;i++)
{
long long u=e[i].u,v=e[i].v;
ans=ans+(size[getfather(u)]*size[getfather(v)]-1)*(e[i].w+1);
unionn(u,v);
}
printf("%lld",ans);
return 0;
}

原文地址:https://www.cnblogs.com/ziliuziliu/p/5096956.html