树剖学的好啊。。。
先预处理出来每个询问的距离,然后二分答案,check的时候树上差分一下,求出来大于mid的询问的最长公共边,减去以后判一下行不行。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=300006;
struct Edge{int to,nxt,val;}e[N<<1];
int head[N],ecnt,n,m,fa[N],dep[N],son[N],siz[N],dis[N],dfn[N],top[N],tim,vis[N],rnk[N],cost[N];
struct Q{int x,y,len;}q[N];
void add(int &bg,int &ed,int &val){e[++ecnt].nxt=head[bg];e[ecnt].to=ed;e[ecnt].val=val;head[bg]=ecnt;}
void dfs1(int x) {
siz[x]=1;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(v==fa[x]) continue;
cost[v]=e[i].val;
fa[v]=x;dep[v]=dep[x]+1;dis[v]=dis[x]+e[i].val;
dfs1(v);
siz[x]+=siz[v];
if(siz[son[x]]<siz[v] ) son[x]=v;
}
}
void dfs2(int x,int qtop) {
dfn[x]=++tim;top[x]=qtop;rnk[tim]=cost[x];
if(son[x]) dfs2(son[x],qtop);
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].to;
if(v==fa[x]||v==son[x]) continue;
dfs2(v,v);
}
}
int lca(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
bool cmp(Q x,Q y) {return x.len>y.len;}
int f[N];
void cf(int x,int y) {
while(top[x]!=top[y]) {if(dep[top[x]]<dep[top[y]])swap(x,y);f[dfn[top[x]]]++,f[dfn[x]+1]--,x=fa[top[x]];}
if(x==y) return;
if(dep[x]>dep[y])swap(x,y);
f[dfn[x]+1]++,f[dfn[y]+1]--;
}
int check(int &tim) {
int cnt=1;
while(q[cnt].len>tim) cnt++;
cnt--;
if(vis[cnt]) return vis[cnt];
memset(f,0,sizeof f);
for(int i=1;i<=cnt;i++)
cf(q[i].x,q[i].y);
int ans=0,mx=0;
for(int i=1;i<=n;i++) {
ans+=f[i];
if(ans==cnt) mx=max(mx,rnk[i]);
}
return vis[cnt]=mx;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1,a,b,c;i<n;i++) {
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);add(b,a,c);
}
dfs1(1),dfs2(1,1);
for(int i=1,a,b;i<=m;i++)
scanf("%d%d",&q[i].x,&q[i].y),q[i].len=dis[q[i].x]+dis[q[i].y]-(dis[lca(q[i].x,q[i].y)]<<1);
sort(q+1,q+1+m,cmp);
int l=0,r=q[1].len;
while(l<=r) {
int mid=l+r>>1;
if(q[1].len-check(mid)>mid) l=mid+1;
else r=mid-1;
}
printf("%d",l);
}