jzoj2940. 生成输入数据

Description

首先看到题目别太开心,这题可不是让你出数据~^_*
背景神马的就忽略了。这题就是给你一棵带边权的树,然后这棵树是某个完全图唯一的最小生成树。问原来的完全图中所有边可能的最小边权和是多少。
完全图是任意两个点之间都有边相连的图。

Input

第一行包含一个整数T表示数据组数。
每组数据第一行一个整数N表示点数。
接下来N-1行每行三个整数ai,bi,wi表示最小生成树上ai和bi之间有一条权值为wi的边。

Output

输出应有T行,每行表示一组数据的答案。

Sample Input

2
3
1 2 4
2 3 7
4
1 2 1
1 3 1
1 4 2

Sample Output

19
12

Data Constraint

20%的数据满足:T≤5,n≤5,wi≤5
另外30%的数据满足:n≤1000,给定的树是一条链
100%的数据满足:T≤10,n≤20000,wi≤10000

题解

这里是一道小技巧题。
我们发现,由于MST是唯一的,那么我们就可以发现,任意不相邻的两点之间都有一条新边且这条新边正好是树上两点间路径最大值+1.
有点绕口。
然后,50分就很好打了。
先上个链剖
我们暴力枚举任意两点,然后统计答案即可。

100分呢?
先从小到大枚举边,把当前的边加入图中。
然后询问当前边所连通的两个连通块的大小分别是什么。
然后乘起来即可。
为什么?
由于我们是从小到大加入边的,所以我们当前的边两端的点之间若是要连接,那么必定经过当前边。
而且当前边是两点之间最大的边,所以可以直接乘起来加入答案。
利用并查集维护连通块大小即可。

很棒的一个小技巧!

代码
uses math;
var
        i,j,k,l,n,m,num,tot,ans,gs,a,b,c,o,xx,yy,jl,t:longint;
        f,v,x,y,z,father:array[1..150000] of longint;
        size:array[1..150000] of int64;
        answer:int64;
procedure qsort(l,r:longint);
var
        i,j:longint;
        mid,k:int64;
begin
        i:=l;
        j:=r;
        mid:=z[(i+j) div 2];
        repeat
                while (z[i]<mid) do inc(i);
                while (z[j]>mid) do dec(j);
                if i<=j then
                begin
                        k:=z[i];
                        z[i]:=z[j];
                        z[j]:=k;
                        k:=x[i];
                        x[i]:=x[j];
                        x[j]:=k;
                        k:=y[i];
                        y[i]:=y[j];
                        y[j]:=k;
                        inc(i);
                        dec(j);
                end;
        until i>j;
        if l<j then qsort(l,j);
        if r>i then qsort(i,r);
end;
function getfather(x:longint):longint;
begin
        if father[x]=x then exit(x);
        father[x]:=getfather(father[x]);
        exit(father[x]);
end;
begin
        readln(t);
        while t>0 do
        begin
        dec(t);
        readln(n);
        answer:=0;
        for i:=1 to n-1 do
        begin
                readln(x[i],y[i],z[i]);
                answer:=answer+z[i];
        end;
        qsort(1,n-1);
        for i:=1 to n do
        begin
                father[i]:=i;
                size[i]:=1;
        end;
        o:=0;
        for i:=1 to n-1 do
        begin
                xx:=getfather(x[i]);
                yy:=getfather(y[i]);
                father[xx]:=yy;
                answer:=answer+(size[xx]*size[yy]-1)*(z[i]+1);
                size[yy]:=size[yy]+size[xx];
        end;
        writeln(answer);
        end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值