运输计划
运输计划
我们考虑先预处理出 LCA、每条路径的长度。
然后发现这个问题具有二段性,所以可以使用二分。
对于<=mid的路径,我们不需要删除边;对于>mid的路径,我们需要删除至少一条边,根据题目条件,所以当且仅当删除一条。
如何求解这些>mid的路径的公共要求的路径呢?可以考虑树上差分,对于 \((u,v),d_u\leftarrow d_u+1,d_v\leftarrow d_v+1,d_{lca}\leftarrow d_{lca}-2\),这里边上的差分用下方的点表示。我们对于每个点求子树和,看那些点的点权恰好为>mid的路径数量,那么这些边就是公共边。然后我们只需要对路径最长的路径分别枚举删除一条公共边,只要有一种方案,就是合法的。注意求子树和可以利用dfs序的逆序,预处理,这样就只需要一遍迭代,无需递归了。
#include<cstdio>
#include<iostream>
#include<cassert>
#include<cstring>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while
const int N=300010,K=19,M=2*N;
int n,m,f[N][K],d[N],de[N],s[N],seq[N],tmp;
int h[N],e[M],ne[M],w[M],idx;//don't forget memset h!
void add(int a,int b,int c){
w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
struct path{
int a,b,p,v;
}p[N];
void dfs(int x,int fa){
// cout<<x<<' '<<fa<<'\n';
// assert(!d[1]);
seq[++tmp]=x;
de[x]=de[fa]+1;
Ed{
int j=e[i];
if(j==fa)continue;
d[j]=d[x]+w[i];
f[j][0]=x;
E(k, K-1)f[j][k]=f[f[j][k-1]][k-1];
dfs(j,x);
}
}
int lca(int a,int b){
if(de[a]>de[b])swap(a,b);
Re(i, K-1, 0)
if(de[f[b][i]]>=de[a])b=f[b][i];
if(a==b)return a;
Re(i, K-1, 0)
if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
return f[a][0];
}
bool check(int mid){
memset(s+1,0,n*4);
int cnt=0,mx=0;
E(i, m){
auto[a,b,p,v]=::p[i];
if(v>mid){
++s[a],++s[b],s[p]-=2;
++cnt;
mx=max(mx,v);
}
}
if(!cnt)return 1;
Re(i, n, 1){
int j=seq[i];
s[f[j][0]]+=s[j];
}
E(i, n)
if(s[i]==cnt&&mx-(d[i]-d[f[i][0]])<=mid)return 1;
return 0;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
memset(h,-1,n*4+4);
E(i, n-1){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
dfs(1,0);
// E(i, n)cout<<d[i]<<' ';
// cout<<'\n';
E(i, m){
int a,b;
cin>>a>>b;
int p=lca(a,b),v=d[a]+d[b]-d[p]*2;
// cout<<a<<' '<<b<<' '<<p<<'\n';
::p[i]={a,b,p,v};
}
int l=0,r=3e8;
Wh(l<r){
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<r;
return 0;
}