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:
- 比较裸的题了…
- 初始,我们预处理出每个树的直径,求出直径上最佳的中点 m i d mid mid( d = m i n { m a x { d i s [ m i d ] , d i s [ R ] − d i s [ m i d ] } } d=min\{max\{dis[mid],dis[R]-dis[mid]\}\} d=min{max{dis[mid],dis[R]−dis[mid]}}),拿这些中点来连边。
- 最优的连边策略,一定是拿拥有最长的 d d d的中点与其它中点建边。
- 建完边后再求一遍直径即为答案。
Code:
#include<bits/stdc++.h>
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 DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmin(T&x,T y){return x>y?x=y,1:0;}
template<class T>inline bool chkmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>inline 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;
}