给出一棵有 n n n个结点的树,有 m m m个人,同时从某个地方 u i u_{i} ui出发,去往另一个地方 v i v_{i} vi。可以选择一条边,使得这条边的长度为 0 0 0,问最早什么时候能让所有人都到达终点?
即需要让这 m m m个花费时间的最大值最小,我们可以二分答案,二分一个时间 t t t,看是否在时间 t t t之内,让所有人到达终点,这是有二分单调性的,一般来说,二分的不是具体数值,而是一类具有”至少“,”至多“这样特性的东西,此处二分的即最多 x x x时间,能否让所有人都到达终点,找到第一个符合条件的 x x x就是答案
接下来考虑如何 c h e c k check check,如果需要所有路径都在 x x x时间内到达目的地,至少原本需要的时间 t ≤ x t\leq x t≤x的一定是可以做到的,只需要考虑 t > x t>x t>x的路径,由于只能选择一条路径,所以我们需要找出他们是否存在交集,这可以通过路径覆盖得到,路径覆盖又可以通过树上差分实现。假设 t > x t>x t>x的路径有 k k k条,只需要找到一条边,使得经过这条边的路径数为 k k k,并且删去这条边能让最长的那条道路在 x x x时间内到达,那么所有道路都可以到达,否则,找不到一条符合这个条件的边,就不可能实现在 x x x时间内都到达了
需要找出他们中大于 x x x的部分和最长的那条路径,先排序是个不错的常熟优化的选择,时间复杂度为 O ( ( n + m ) l o g C ) O((n+m)logC) O((n+m)logC), C C C为二分长度
// #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using ll=long long;
const int N=300005,inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f,mod=1e9+7;
struct node
{
int u,v,dis,x;
}a[N];
struct way
{
int to,next,w;
}edge[N<<2];
int cntt,head[N<<1];
void add(int u,int v,int w)
{
edge[++cntt].to=v;
edge[cntt].w=w;
edge[cntt].next=head[u];
head[u]=cntt;
}
int n,m,f[N<<1][21],depth[N<<1],sum[N<<1],tot,belong[N<<1];
void dfs1(int u,int fa)
{
f[u][0]=fa; depth[u]=depth[fa]+1;
for(int i=1;i<=20;i++) f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to,w=edge[i].w;
if(v==fa) continue;
sum[v]=sum[u]+w;
dfs1(v,u);
}
}
int lca(int x,int y)
{
if(depth[x]<depth[y]) swap(x,y);
for(int i=20;i>=0;i--)
if(depth[f[x][i]]>=depth[y]) x=f[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int dis(int x,int y,int& tmp){return sum[x]+sum[y]-2*sum[tmp=lca(x,y)];}
int del[N<<1],val[N<<1];
void dfs(int u,int fa)
{
val[u]=del[u];
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
dfs(v,u);
val[u]+=val[v];
}
}
bool check(int x)
{
int cnt=0;
for(int i=1;i<=m;i++)
{
if(a[i].dis>x)
{
auto& [u,v,dis,x]=a[i]; cnt++;
del[u]++; del[v]++; del[x]--; del[f[x][0]]--;
}
else break;
}
dfs(1,0);
auto initial=[&]()
{
for(int i=1;i<=m;i++)
{
if(a[i].dis>x)
{
auto& [u,v,dis,x]=a[i];
del[u]--; del[v]--; del[x]++; del[f[x][0]]++;
}
else break;
}
};
for(int i=n+1;i<=tot;i++)
{
if(val[i]==cnt&&a[1].dis-belong[i]<=x)
{
initial();
return true;
}
}
initial();
return false;
}
int read()
{
int ret=0,base=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') base=0;
ch=getchar();
}
while(isdigit(ch))
{
ret=ret*10+ch-48;
ch=getchar();
}
return base?ret:-ret;
}
int main()
{
n=tot=read(); m=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read(),w=read();
belong[++tot]=w;
add(u,tot,w); add(tot,u,w);
add(v,tot,0); add(tot,v,0);
}
dfs1(1,0);
for(int i=1;i<=m;i++)
{
auto& [u,v,dis,x]=a[i];
u=read(); v=read(); dis=::dis(u,v,x);
}
sort(a+1,a+1+m,[&](const node& x,const node& y){
return x.dis>y.dis;
});
int l=0,r=inf,ans;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans;
return 0;
}