Description:
有 n n n个点 m m m条边的图,现在加 n − 1 − m n-1-m n−1−m条长度为 L e n Len Len的边使之变为一棵树,求树的直径的最小值。
n ≤ 1 0 5 n\le10^5 n≤105
Solution:
Code:
#include
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i=i##_end_;--i)
#define ll long long
templateinline bool chkmin(T&x,T y){return x>y?x=y,1:0;}
templateinline bool chkmax(T&x,T y){return xinline void rd(T&x){
x=0;char c;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
const int N=1e5+2,INF=0x3f3f3f3f;
int n,m;
ll Len;
int qwq,head[N];
struct edge{
int to,nxt;
ll w;
}E[N<<1];
void addedge(int x,int y,ll z){E[qwq]=(edge){y,head[x],z};head[x]=qwq++;}
#define EREP(x) for(int i=head[x];~i;i=E[i].nxt)
struct p100{
ll dis[N];
int fa[N];
ll Mn[N];// 每个小树的 min{max{dis[L][mid],dis[mid][R]}}
int rt[N],cnt;// 每个小树的中点
bool vis[N];
int Id;
ll Mx;
void dfs1(int x,int f,ll d){
if(chkmax(Mx,d)) Id=x;
vis[x]=1;
EREP(x){
int y=E[i].to;
if(y==f)continue;
dfs1(y,x,d+E[i].w);
}
}
void dfs2(int x,int f,ll d){
if(chkmax(Mx,d)) Id=x;
fa[x]=f;
dis[x]=d;
EREP(x){
int y=E[i].to;
if(y==f)continue;
dfs2(y,x,d+E[i].w);
}
}
void solve(){
REP(i,1,n) if(!vis[i]) {
Id=Mx=-1;
dfs1(i,0,0);
rt[++cnt]=Id;//L
Mx=-1;
dfs2(Id,0,0);//R
int R=Id,L=rt[cnt],mid=R;
Mn[cnt]=INF;
if(L==R) Mn[cnt]=0;
while(mid!=L){
if(chkmin(Mn[cnt],max(dis[mid],dis[R]-dis[mid])))rt[cnt]=mid;
mid=fa[mid];
}
}
ll mx1=-1;
int Rt1=-1;
REP(i,1,cnt)if(chkmax(mx1,Mn[i])) Rt1=rt[i];
REP(i,1,cnt){
if(Rt1==rt[i])continue;
addedge(Rt1,rt[i],Len);
addedge(rt[i],Rt1,Len);
}
Mx=Id=-1;
dfs1(1,0,0);
Mx=-1;
dfs2(Id,0,0);
printf("%lld\n",Mx);
}
}p2;
int main(){
// freopen("dreaming.in","r",stdin);
// freopen("dreaming.out","w",stdout);
rd(n),rd(m),rd(Len);
memset(head,-1,sizeof head);
REP(i,1,m){
int a,b,c;
rd(a),rd(b),rd(c);
++a,++b;
addedge(a,b,c);
addedge(b,a,c);
}
p2.solve();
return 0;
}