#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e6+10;
int n,m;
//存图
int head[N],to[N<<1],e[N<<1],nxt[N<<1],tot;
//lca
int deep[N],f[N][20];
int seq[N],dist[N],cnt;//seq[]存储dfs的顺序,dist[x]表示x到根的距离
//差分数组
int sum[N];
struct Path
{
int a,b;//路径的端点
int lca,dist;//a 和 b的最近公共祖先,路径长度
}path[N];
void add(int a,int b,int c)
{
to[++tot]=b;
e[tot]=c;
nxt[tot]=head[a];
head[a]=tot;
}
void dfs(int x)
{
seq[++cnt]=x;
for(int i=1;i<20;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=head[x];i;i=nxt[i])
{
int y=to[i],w=e[i];
if(f[x][0]==y) continue;
deep[y]=deep[x]+1;
dist[y]=dist[x]+w;
f[y][0]=x;
dfs(y);
}
}
int lca(int x,int y)
{
//先跳y
if(deep[x]>deep[y]) swap(x,y);
for(int i=19;i>=0;i--)
{
if(deep[f[y][i]]>=deep[x])
y=f[y][i];
}
if(x==y) return x;
for(int i=19;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i],y=f[y][i];
}
}
return f[x][0];
}
//当能找到一个公共边删除后,使得所有路径都小于等于mid
bool check(int mid)
{
memset(sum,0,sizeof(sum));
int cnt=0,maxd=0;//cnt表示路径种大于mid的数量,maxd大于mid的路径的最大值
for(int i=1;i<=m;i++)
{
if(path[i].dist>mid)
{
cnt++;
maxd=max(maxd,path[i].dist);
sum[path[i].a]++,sum[path[i].b]++;
sum[path[i].lca]-=2;
}
}
if(cnt==0) return true;//没有任何一条边大于mid
//利用刚刚记录的dfs序列计算差分的和
for(int i=n;i;i--)
sum[f[seq[i]][0]]+=sum[seq[i]];
for(int i=1;i<=n;i++)
{
//当这条边时公共边,同时这条边的距离大于
int w=dist[i]-dist[f[i][0]];
if(sum[i]==cnt && maxd-w<=mid)
return true;
}
return false;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n-1;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
deep[1]=1;
dfs(1);
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
int p=lca(a,b);
path[i]=(Path){a,b,p,dist[a]+dist[b]-dist[p]*2};
}
int l=0,r=1e9;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))//当check为true说明mid取大了
r=mid;
else//否则说明取小了
l=mid+1;
}
cout<<r;
return 0;
}
共 2 条回复
%%%(
%%%