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.
我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。