传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3246
很容易想到是连接各树重心
处理每棵树直径和最大深度,连接后的树的直径会由以下三方面贡献:
原本的直径
最深树和次深树构成的直径
次深树和次次深树构成的直径
(写给我自己的注意事项:一个儿子只能贡献最长链或者次长链中的一个)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define cint const int &
#define inf 1000000000000000000LL
#define N 500005
int tot,s[N],f[N],n,m,L;
ll d1[N],d2[N],mn,ans;
priority_queue<ll> Q;
struct edge{int v,c,n;}e[N<<1];
inline void push(cint u,cint v,cint c){e[++tot]=(edge){v,c,s[u]};s[u]=tot;}
#define Push(u,v,c) push(u,v,c),push(v,u,c);
void down(cint k,cint fa=-1)
{
f[k]=fa;
for (int i=s[k];i;i=e[i].n) if (!f[e[i].v])
{
down(e[i].v,k);
if (d1[k]<=d1[e[i].v]+e[i].c) d2[k]=d1[k],d1[k]=d1[e[i].v]+e[i].c;
else d2[k]=max(d2[k],d1[e[i].v]+e[i].c);
}
ans=max(ans,d1[k]+d2[k]);
}
void up(cint k,const ll &u=0)
{
mn=min(mn,max(u,d1[k]));ans=max(ans,u+d1[k]);
for (int i=s[k];i;i=e[i].n) if (e[i].v!=f[k]) up(e[i].v,max(u,(d1[e[i].v]+e[i].c==d1[k]?d2[k]:d1[k]))+e[i].c);
}
inline void pre(cint k)
{
down(k);
mn=inf;
up(k);
Q.push(mn);
}
int main()
{
scanf("%d%d%d",&n,&m,&L);
for (int i=1,u,v,c;i<=m;++i)
{
scanf("%d%d%d",&u,&v,&c);
Push(u+1,v+1,c);
}
for (int i=1;i<=n;++i) if (!f[i]) pre(i);
ll k1=-inf/2,k2=-inf/2,k3=-inf/2;
if (!Q.empty()) k1=Q.top(),Q.pop();
if (!Q.empty()) k2=Q.top(),Q.pop();
if (!Q.empty()) k3=Q.top(),Q.pop();
printf("%lld",max(ans,max(k1+k2+L,k2+k3+L*2)));
}