总的来说,这是一道考图论知识的题,可以搜到很多关于树的直径的东西,以及一些证明,这是一道好题!
program shigong;
type arr=array[1..200000]of longint;
var n,m,tot,{边数}
one,{以节点1为树根时dfs得到的最远点}
two:longint;{以one为树根时dfs得到的最远点,d(one,two)既为树的直径}
max:int64;{最远的路径}
x,y,w:array[1..200000]of longint;{初始边}
f,{并查集中用作父亲节点,清零后在dfs中用来存每个点的前驱}
d:array[1..100000]of longint;{记录每个点到树根的路径长度}
mstx,msty,mstw:array[1..200000]of longint;{存最小生成树}
s,t:array[1..100000]of longint;{每个节点作为有向边起点时连接的边编号范围}
v:array[1..100000]of boolean;{标志数组避免dfs重复访问}
procedure init;
var i:longint;
begin
read(n);read(m);
for i:=1 to m do
begin
read(x[i]);read(y[i]);read(w[i]);
end;
end;
procedure qsort(l,r:longint;var a,b,c:arr);{快排的设计很巧妙}
var i,j,x,y:longint;
begin
i:=l;j:=r;
x:=a[(l+r)shr 1];
repeat
while a[i]<x do inc(i);
while a[j]>x do dec(j);
if i<=j then begin
y:=a[i];a[i]:=a[j];a[j]:=y;
y:=b[i];b[i]:=b[j];b[j]:=y;
y:=c[i];c[i]:=c[j];c[j]:=y;
inc(i);dec(j);
end;
until i>j;
if i<r then qsort(i,r,a,b,c);
if j>l then qsort(l,j,a,b,c);
end;
function find(p:longint):longint;
begin
if f[p]=p then exit(p);
f[p]:=find(f[p]);
exit(f[p]);
end;
procedure union(a,b:longint);
var x,y:longint;
begin
x:=find(a);y:=find(b);
f[x]:=y;
end;
function same(a,b:longint):boolean;
begin
if find(a)=find(b) then exit(true);
exit(false);
end;
procedure kruskal;
var i:longint;ans:int64;
begin
qsort(1,m,w,x,y);{此处按权值排序}
for i:=1 to n do f[i]:=i;
ans:=0;tot:=0;
for i:=1 to m do
if not same(x[i],y[i]) then
begin
inc(ans,w[i]);
union(x[i],y[i]);
inc(tot);
mstx[tot]:=x[i];
msty[tot]:=y[i];
mstw[tot]:=w[i];
if tot=n-1 then break;
end;
writeln(ans);
end;
procedure prepare;
var i:longint;
begin
for i:=1 to tot do
begin
mstx[n+i-1]:=msty[i];
msty[n+i-1]:=mstx[i];
mstw[n+i-1]:=mstw[i];
end;
tot:=tot*2;
qsort(1,tot,mstx,msty,mstw);{注意:此处按始节点排序}
s[mstx[1]]:=1;
t[mstx[tot]]:=tot;
for i:=1 to tot do
begin
if (i>1)and(mstx[i]<>mstx[i-1]) then s[mstx[i]]:=i;
if (i<tot)and(mstx[i]<>mstx[i+1]) then t[mstx[i]]:=i;
end;
end;
procedure dfs(p:longint);
var i:longint;
begin
v[p]:=true;
for i:=s[p] to t[p] do
if not v[msty[i]] then
begin
d[msty[i]]:=d[p]+mstw[i];
if max<d[msty[i]] then
begin two:=msty[i];max:=d[msty[i]];end;
f[msty[i]]:=p;
dfs(msty[i]);
end;
end;
function min(a,b:longint):longint;
begin
if a<b then exit(a);
exit(b);
end;
function maxx(a,b:longint):longint;
begin
if a>b then exit(a);
exit(b);
end;
procedure main;
var now,ans:int64;
begin
fillchar(v,sizeof(v),false);
max:=0;two:=1;
dfs(mstx[1]);
one:=two;max:=0;
fillchar(d,sizeof(d),0);
fillchar(v,sizeof(v),false);
fillchar(f,sizeof(f),0);
dfs(one);
now:=0;ans:=maxlongint;
while two<>one do
begin
ans:=min(ans,maxx(now,max-now));{寻找在树的直径上距离两端路径长度的最大 值最小的点,此节点即为所求,根据直径的定义,可以知道在直径之外的点到这 点的路径长<=这个最小的最大值,否则这条就不是直径了,所以此法正解}
now:=now+d[two]-d[f[two]];
two:=f[two];
end;
write(ans);
end;
begin
init;
kruskal;
prepare;
main;
end.