用的是二分答案+树上差分。
求lca用的是tarjan。
求完lca后重新dfs了一遍,复用了一些数组。
验证答案的时候是按照dfs得到的后序遍历的顺序循环的,保证每个节点都在所有子节点访问到后才被访问。
'''cpp
#include<cstdio>
#include<cstring>
#include<algorithm>
int n,m,cnt,head[300001],qcnt,qhead[300001],d[300001],idx,fa[300001],f[300001],max,road[300001],vis[300001];
bool u[300001];
struct edge{
int nxt,to,d;
}e[600001];
struct query{
int nxt,to,idx;
}q[600001];
struct qinfo{
int x,y,lca,d;
}info[300001];
int get(){
int num=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9'){
num=(num<<1)+(num<<3)+c-'0';
c=getchar();
}
return num;
}
inline void add(int x,int y,int z){
++cnt;
e[cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].d=z;
head[x]=cnt;
}
inline void qadd(int x,int y,int z){
++qcnt;
q[qcnt].nxt=qhead[x];
q[qcnt].to=y;
q[qcnt].idx=z;
qhead[x]=qcnt;
}
int find(int x){
if(fa[x]==0) return x;
else return fa[x]=find(fa[x]);
}
void lca(int x,int deep){
int v;
u[x]=true; d[x]=deep;
for(int i=head[x];i;i=e[i].nxt){
v=e[i].to;
if(!u[v]){
lca(v,deep+e[i].d);
fa[v]=x;
}
}
for(int i=qhead[x];i;i=q[i].nxt){
v=q[i].to;
if(u[v]){
idx=q[i].idx;
info[idx].x=x;
info[idx].y=v;
info[idx].lca=find(v);
info[idx].d=deep+d[v]-(d[fa[v]]<<1);
}
}
}
void initdfs(int x){
int v;
for(int i=head[x];i;i=e[i].nxt){
v=e[i].to;
if(v!=fa[x]){
fa[v]=x; d[v]=e[i].d;
initdfs(v);
}
}
vis[++vis[0]]=x;
}
bool comp(const qinfo &a,const qinfo &b){
return a.d>b.d;
}
bool check(int ans){
cnt=0;
memset(road,0,sizeof(road));
for(int i=1;i<=m;++i){
if(info[i].d<=ans) break;
++road[info[i].x]; ++road[info[i].y]; road[info[i].lca]-=2;
++cnt;
}
int v;
for(int i=1;i<n;++i){
v=vis[i];
if(road[v]==cnt && max-d[v]<=ans) return true;
road[fa[v]]+=road[v];
}
return false;
}
int main(){
n=get(); m=get();
int a,b,t;
for(int i=1;i<n;++i){
a=get(); b=get(); t=get();
add(a,b,t); add(b,a,t);
}
for(int i=1;i<=m;++i){
a=get(); b=get();
qadd(a,b,i); qadd(b,a,i);
}
lca(1,0);
initdfs(1);
std::sort(info+1,info+m+1,comp);
int l=0,r=max=info[1].d,mid;
while(l<r){
mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%d",l);
return 0;
}
'''