Loj10067 构造完全图

题目描述

对于完全图 G,若有且仅有一棵最小生成树为 T,则称完全图 G 是树 T 扩展出的。

给你一棵树 T,找出 T 能扩展出的边权和最小的完全图 G。

输入格式

第一行 N 表示树 T 的点数;

接下来 N−1 行三个整数 Si,Ti,Di;描述一条边(Si,Ti)权值为 Di​​;

保证输入数据构成一棵树。

输出格式

输出仅一个数,表示最小的完全图 G 的边权和。

样例

样例输入

4  
1 2 1  
1 3 1  
1 4 2

样例输出

12

这道题解法很巧妙,还是从小到大排序,一条一条往上加。
往上加的同时,记录sum[i]表示以i为根节点的树中含点的个数,很显然,一次操作中所加的边权就是(sum[i]+sum[j]-1)*(v+1)+v其中i表示加入边的起点,j表示终点,v表示边权

代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
#define MAXN 100010
#define INF 2147483647
#define MOD 10000007
#define LL long long
#define in(a) a=read()
#define REP(i,k,n) for(int i=k;i<=n;i++)
#define DREP(i,k,n) for(int i=k;i>=n;i--)
#define cl(a) memset(a,0,sizeof(a))
inline int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
inline void out(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) out(x/10);
    putchar(x%10+'0');
}
int n;
LL ans=0;
LL f[100010],sum[100010];
struct node{
    int a,b,c;
}tree[100010];
bool cmp(node x,node y){
    return x.c<y.c;
}
int getf(int k){
    if(f[k]==k)  return f[k];
    return f[k]=getf(f[k]);
}
int main(){
    in(n);
    REP(i,1,n-1){
        in(tree[i].a);in(tree[i].b);in(tree[i].c);
    }
    sort(tree+1,tree+n,cmp);
    REP(i,1,n)  sum[i]=1,f[i]=i;
    REP(i,1,n-1){
        int x=getf(tree[i].a),y=getf(tree[i].b);
        if(x!=y){
            ans+=(sum[x]*sum[y]-1)*(tree[i].c+1)+tree[i].c;
            f[y]=x;
            sum[x]+=sum[y];
    //        cout<<x<<" "<<y<<" "<<f[y]<<" "<<sum[x]<<" "<<ans<<endl;
        }
    }
    cout<<ans;
    return 0;
}


 
原文地址:https://www.cnblogs.com/jason2003/p/9636584.html