2940. 【NOIP2012模拟8.10】生成输入数据

jzoj2940. 生成输入数据 (Standard IO)

题目大意:

给你一棵带边权的树,然后这棵树是某个完全图唯一的最小生成树。问原来的完全图中所有边可能的最小边权和是多少。

(完全图是任意两个点之间都有边相连的图。)

题解

考虑最小生成树的定义,若我们先按照树边边权从小到大排序,一条边两端的联通块中任意一组点对(除与这条树边直接相连的两点)对答案的贡献都是该树边边权加一。为什么?因为该边是两联通块中任一点对的路径上最小值,而题目中强调“唯一的最小生成树”,故上结论成立。

代码如下:

#include<cstdio>
#include<algorithm>

using namespace std;

const int N = 2e4 + 100;
inline void read(int &x)
{
    x = 0;char c = getchar();
    while(c > '9' || c < '0') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0' , c = getchar();
}

struct note
{
    int u , v , val;
    bool operator <(const note &a)
    const
    {
        return val < a.val;
    }

    inline void getin(){read(u) , read(v) ,read(val);}
}g[N];

int t , n , size[N] , fa[N];

inline int getfa(int x){return x == fa[x] ? fa[x] : getfa(fa[x]);}

int main()
{
    for(read(t) ; t ; t --)
    {
        read(n);long long ans = 0;
        for(int i = 1;i < n;i ++) g[i].getin();
        for(int i = 1;i <= n;i ++) fa[i] = i , size[i] = 1;

        sort(g + 1 , g + n);
        for(int i = 1;i < n;i ++)
        {
            int x = getfa(g[i].u) , y = getfa(g[i].v);
                
            if(size[x] < size[y]) x ^= y ^= x ^= y;
            ans += 1ll * (g[i].val + 1) * size[x] * size[y] - 1, size[x] += size[y] , fa[y] = x;    
        }

        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Sin-demon/p/10293503.html