考慮在樹上選個點rt作為根,並且快遞中心就選這兒。計算出所有配送的代價(2*兩段之和),設他們的最大值為Max。若此時存在下列情況時,可以判定Max已經為最優解。
1)存在代價為Max的配送(u,v)且uv分別屬於rt的不同的兩個“兒子的子樹”。
2)存在代價為Max的配送(u1,v1)(u2,v2)且u1u2分別屬於rt的不同的兩個“兒子的子樹”。
3)存在代價為Max的配送(u1,v1)(u2,v2)且v1v2分別屬於rt的不同的兩個“兒子的子樹”。
但是若1)不存在,2)、3)不就是一種情況了嗎,滑稽。 概括一下就是當所欲代價為Max的配送的端點所屬於的“兒子的子樹”不唯一,則已達到最優解,證明就上邊那三種情況。
如果都不滿足的話,那麼更優的選點應在Max的配送(u,v)的u(=v)所屬於的那個“兒子的子樹”裡。分治下去就好。
【實現】
int n,m;
int head[N],to[M],len[M],last[M];
int sum,rt,qu[N],qv[N],fiz[N],siz[N],dis[N],bel[N];
bool ban[N];
void addEdge(int x,int y,int w) {
static int cnt=0;
to[++cnt]=y;
len[cnt]=w;
last[cnt]=head[x];
head[x]=cnt;
}
void getRoot(int x,int pa) {
fiz[x]=0,siz[x]=1;
for(int i=head[x]; i; i=last[i]) {
if(to[i]==pa||ban[to[i]]) continue;
getRoot(to[i],x);
siz[x]+=siz[to[i]];
fiz[x]=max(fiz[x],siz[to[i]]);
}
fiz[x]=max(fiz[x],sum-siz[x]);
if(fiz[x]<fiz[rt]) rt=x;
}
void getDis(int x,int pa,int id) {
bel[x]=id;
for(int i=head[x]; i; i=last[i]) {
if(to[i]==pa) continue;
dis[to[i]]=dis[x]+len[i];
getDis(to[i],x,id);
}
}
int sta[N];
int solveAt(int x) {
if(ban[x]) return 2e9;
ban[x]=1,dis[x]=0;
for(int i=head[x]; i; i=last[i]) {
dis[to[i]]=len[i];
getDis(to[i],x,to[i]);
}
int Max=0,top=0;
for(int i=1; i<=m; ++i) {
if(Max<dis[qu[i]]+dis[qv[i]]) {
Max=dis[qu[i]]+dis[qv[i]];
sta[top=1]=i;
} else if(Max==dis[qu[i]]+dis[qv[i]]) {
sta[++top]=i;
}
}
for(int i=1; i<=top; ++i) {
if(bel[qu[sta[i]]]!=bel[qv[sta[i]]]) return Max;
if(bel[qu[sta[i]]]!=bel[qu[sta[1]]]) return Max;
}
rt=0;
sum=siz[bel[qu[sta[1]]]];
getRoot(bel[qu[sta[1]]],x);
return min(Max,solveAt(rt));
}
int main() {
read(n),read(m);
for(int x,y,w,i=n; --i; ) {
read(x),read(y),read(w);
addEdge(x,y,w);
addEdge(y,x,w);
}
for(int i=1; i<=m; ++i) {
read(qu[i]),read(qv[i]);
}
sum=n; //寫成sum=0瘋狂T
fiz[0]=2e9;
getRoot(1,0);
printf("%d
",solveAt(rt));
return 0;
}