挺难的这道题···
solution:
主要思想是点分治,但和点分治还有点不同,点分治要遍历每个子树的重心,而这个题只会往一个子树的重心跳
在每一层分治中,遍历整棵树每个点到这个root的距离,更新最长距离。
1、考虑到当前距离最长的一些pair,如果已经在某些pair的链上,则已经是最优了,无法使得答案更小,就可以跳出了。
2、否则这个点不在任意最长链上,那么最长链的每一个点对必然在这个点的子树内而不经过这个分治重心。那么越靠近最长链(甚至点在最长链上必然最优)
3、如果所有最长链不在同一个子树里,我们向一边走的时候,另一边不会变小,最大值不会变小,也可以跳出。否则就在最长链都在的这个子树内找到重心分治下去。
总复杂度O(nlogn)
注意一点就是已经走过的root要用vis数组记下来后面所有的操作都不考虑他们了,还有就是点分治特别要注意的,每一次分治都要重新计算下一次分治的总点数!要不然复杂度会不对
代码如下:(因为是改过来的所以写的有点丑)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cctype>
#define N 100005
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
using namespace std;
int n,m,cnt,head[N],dis[N],maxx,bary,siz[N];
int ans=inf,bel[N],q[N][2];
bool vis[N];
inline int rd(){
int x=0,f=0; char ch=0;
while(!isdigit(ch)) f|=ch=='-',ch=getchar();
while( isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
struct EDGE{
int to,nxt,w;
}edge[N<<1];
inline void add(int x,int y,int z){
edge[++cnt].to=y; edge[cnt].w=z;
edge[cnt].nxt=head[x]; head[x]=cnt;
}
inline void find_bary(int tot,int u,int fa){
siz[u]=1; int tmp=0;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to; if(v==fa||vis[v]) continue;
find_bary(tot,v,u);
siz[u]+=siz[v]; tmp=max(tmp,siz[v]);
}
tmp=max(tmp,tot-siz[u]);
if(tmp<maxx) maxx=tmp,bary=u;
return;
}
inline void get_dis(int u,int fa,int rt){
bel[u]=rt; siz[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to; if(v==fa) continue;
dis[v]=dis[u]+edge[i].w;
get_dis(v,u,rt); siz[u]+=siz[v];
} return;
}
inline int get_size(int u,int fa){
int tmp=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(vis[v] || v==fa) continue;
tmp+=get_size(v,u);
} return tmp;
}
inline void solve(int root){
if(vis[root]) return;
vis[root]=1; dis[root]=0; bel[root]=root;
int mx=0;
for(int i=head[root];i;i=edge[i].nxt){
int v=edge[i].to;
dis[v]=edge[i].w;
get_dis(v,root,v);
}
for(int i=1;i<=m;i++){
if(dis[q[i][0]]+dis[q[i][1]]>mx)
mx=dis[q[i][0]]+dis[q[i][1]];
}
ans=min(ans,mx); int tar=-1;
for(int i=1;i<=m;i++)
if(dis[q[i][0]]+dis[q[i][1]]==mx){
if(bel[q[i][0]]!=bel[q[i][1]]) return;
if(tar!=-1 && tar!=bel[q[i][0]]) return;
tar=bel[q[i][0]];
}
if(vis[tar]) return;
maxx=n+1; bary=0;
int tot=get_size(tar,root);
find_bary(tot,tar,root);
solve(bary);
}
signed main(){
n=rd(); m=rd();
for(int i=1;i<n;i++){
int x=rd(),y=rd(),z=rd();
add(x,y,z); add(y,x,z);
}
for(int i=1;i<=m;i++)
q[i][0]=rd(),q[i][1]=rd();
solve(1);
printf("%d\n",ans);
return 0;
}