码迷,mamicode.com
首页 > 其他好文 > 详细

JoyOI1391 走廊泼水节

时间:2018-09-01 23:47:22      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:长度   答案   输入   class   bool   long   cpp   algorithm   time   

一道另类生成树
将输入的树的\(n-1\)条边按从小到大排序,然后\(Kruskal\)在生成该树的过程中计算新增边的总长。
当在连第\(i\)条边,设该边的两端点为\(x,y\),长度为\(z\),分别属于\(S_x\)\(S_y\)两个并查集中。
而为了将树变成完全图,显然要将\(S_x,S_y\)两个并查集中所有点一一连边,所以除去原有的这条边,剩下共\(|S_x|\times|S_y|-1\)条边需要被添加。
而为了使完全图的最小生成树是原有树,所以在添加这\(|S_x|\times|S_y|-1\)条边时,必须使得这些边比原有边要长,同时由于要使得添加的边长和最小,所以这些边的长度均为\(z+1\)
所以总长为\((z+1)\times(|S_x|\times|S_y|-1)\),将其累加至答案即可。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 6010;
struct dd {
    int x, y, z;
};
dd a[N];
int fa[N], S[N];
int re()
{
    int x = 0;
    char c = getchar();
    bool p = 0;
    for (; c<'0' || c>'9'; c = getchar())
        p |= c == '-';
    for (; c >= '0'&&c <= '9'; c = getchar())
        x = x * 10 + (c - '0');
    return p ? -x : x;
}
int fin(int x)
{
    if (fa[x] == x)
        return x;
    return fa[x] = fin(fa[x]);
}
int comp(dd x, dd y)
{
    return x.z < y.z;
}
int main()
{
    int i, x, y, n, t;
    long long s;
    t = re();
    while (t--)
    {
        n = re();
        for (S[n] = i = 1, fa[n] = n; i < n; i++)
        {
            a[i].x = re();
            a[i].y = re();
            a[i].z = re();
            fa[i] = i;
            S[i] = 1;
        }
        sort(a + 1, a + n, comp);
        for (i = 1, s = 0; i < n; i++)
        {
            x = fin(a[i].x);
            y = fin(a[i].y);
            if (x != y)
            {
                s += 1LL * (a[i].z + 1)*(S[x] * S[y] - 1);
                fa[x] = y;
                S[y] += S[x];
            }
        }
        printf("%lld\n", s);
    }
    return 0;
}

ps:因为我用的是\(VS\),所以代码会自动补空格,而我本来的风格是没有空格的。

JoyOI1391 走廊泼水节

标签:长度   答案   输入   class   bool   long   cpp   algorithm   time   

原文地址:https://www.cnblogs.com/Iowa-Battleship/p/9571573.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!