题意:n个点m条双向边,要求去掉一些边仅保留(n-1)条边,每个点有各自的点权,每条边有各自的边权,要求从一个点出发遍历每一个点再回到起点,每经过一次点i,代价就加上一次该点点权,每经过一次边j,代价就加上一次该边的边权。求最小的代价
每一条边对答案的贡献 = 该边的边权*2 + 两端点点权
以此作为它的边权跑最小生成树
然后我们会发现,作为起点的点又额外加了一次,而对于我们求出的最小生成树,无论选哪个点为起点,所需的代价是一样的即新边权的和
我们只需要选择点权最小的点作为起点,最后将答案加上它一次即可
type
rec=record
x,y,len:longint;
end;
var
n,m,tt,ans,tx,ty:longint;
i :longint;
w,father :array[0..10010] of longint;
l :array[0..100010] of rec;
function get_father(x:longint):longint;
begin
if x=father[x] then exit(x);
father[x]:=get_father(father[x]);
exit(father[x]);
end;
procedure sort(ll,rr:longint);
var
i,j,x:longint;
y:rec;
begin
i:=ll; j:=rr; x:=l[(ll+rr)>>1].len;
while (i<=j) do
begin
while l[i].len<x do inc(i);
while l[j].len>x do dec(j);
if i<=j then
begin
y:=l[i]; l[i]:=l[j]; l[j]:=y;
inc(i); dec(j);
end;
end;
if i<rr then sort(i,rr);
if j>ll then sort(ll,j);
end;
begin
read(n,m); ans:=maxlongint;
for i:=1 to n do
begin
read(w[i]);
if w[i]<ans then ans:=w[i];
end;
for i:=1 to n do father[i]:=i;
for i:=1 to m do
begin
read(l[i].x,l[i].y,l[i].len);
l[i].len:=l[i].len*2+w[l[i].x]+w[l[i].y];
end;
sort(1,m); tt:=0;
for i:=1 to m do
begin
tx:=get_father(l[i].x);
ty:=get_father(l[i].y);
if tx<>ty then
begin
father[tx]:=ty;
inc(ans,l[i].len);
inc(tt);
if tt=n-1 then break;
end;
end;
writeln(ans);
end.
——by Eirlys