LOJ10067

LOJ10067

由原树,生成唯一的最小完全图——
类似Kruscal的想法:
初始时将每个节点理解为自成一个联通块,按边权从小到大处理,每次合并联通块:
设当前连X与Y,X所在联通块有cnt[fx]个节点,Y所在有cnt[fy]个
两块连接后,由于要构成完全图,显然有(cnt[fx]*cnt[fy]-1)条边(除去已连的一条)
至于代价,由于要保证生成的完全图中最小生成树不变,自然边权+1
所以很明显, Ans+=(cnt[fx]cnt[fy]1)(a[i].w+1),fa[fx]=fy,cnt[fy]+=cnt[fx] A n s + = ( c n t [ f x ] ∗ c n t [ f y ] − 1 ) ∗ ( a [ i ] . w + 1 ) , f a [ f x ] = f y , c n t [ f y ] + = c n t [ f x ] (i=1~N-1,挑完N-1条就好)
但是,这一定是符合条件的最优解吗?
完全图,两两相连
这样从小到大处理,那么X所在的联通块中的节点和Y中的节点肯定没有更短的边连了,才会轮到它们连
同时,因为边权加了1,要最小生成树的边也恰好轮不到它们——
这样就完美符合题意了!

#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define LL long long
using namespace std;
static char buf[1000000],*p1=buf,*p2=buf;
const int maxn=(1e5)+5;
int n,fa[maxn],cnt[maxn];LL ans;
struct ff{
    int x,y,z;
    inline bool operator <(const ff b)const{return z<b.z;}
}a[maxn];
int read(){
    int ret=0;char ch=gt();
    while(ch<'0'||ch>'9') ch=gt();
    while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
    return ret;
}
inline int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
int main(){
    n=read();
    for(int i=1;i<n;i++) a[i]=(ff){read(),read(),read()},ans+=a[i].z;sort(a+1,a+n);
    for(int i=1;i<=n;i++) cnt[i]=1,fa[i]=i;
    int fx,fy;
    for(int i=1;i<n;i++){
        fx=getfa(a[i].x),fy=getfa(a[i].y);
        ans+=(LL)((LL)cnt[fx]*cnt[fy]-1)*(a[i].z+1);
        fa[fx]=fy,cnt[fy]+=cnt[fx];
    }
    printf("%lld\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值