考虑二分
把所有超过mid的链取交集,然后取交集上最长的边权赋0,判断
#include<cstdio> #include<cstdlib> #include<algorithm> #define V G[p].v using namespace std; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } struct Seg_SUM{ int M,TH; int T[400005],H[400005]; inline void Build (int n) { for (M=1,TH=0;M<n+2;M<<=1,TH++); } inline void Add(int s,int t,int c) { for (s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1) { if (~s&1) T[s^1]+=c; if ( t&1) T[t^1]+=c; } } inline int Query(int s) { int ret=0; ret+=T[s+=M]; while (s>>=1) ret+=T[s]; return ret; } }Seg; const int N=300005; struct edge{ int u,v,w,next; }; edge G[2*N]; int head[N],inum; inline void add(int u,int v,int w,int p){ G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p; } int size[N],depth[N],fat[N],dis[N]; int clk,tid[N],top[N]; void dfs(int u,int fa){ fat[u]=fa; depth[u]=depth[fa]+1; size[u]=1; for (int p=head[u];p;p=G[p].next) if (V!=fa) { dis[V]=dis[u]+G[p].w; dfs(V,u),size[u]+=size[V]; } } void find(int u,int fa,int z){ tid[u]=++clk; top[u]=z; int maximum=0,son=0; for (int p=head[u];p;p=G[p].next) if (V!=fa && size[V]>maximum) maximum=size[son=V]; if (son) find(son,u,z); for (int p=head[u];p;p=G[p].next) if (V!=fa && V!=son) find(V,u,V); } inline int LCA(int u,int v){ for (;top[u]!=top[v];u=fat[top[u]]) if (depth[top[u]]<depth[top[v]]) swap(u,v); if (depth[u]>depth[v]) swap(u,v); return u; } int n,m; struct event{ int u,v,lca,dis; }eve[N]; inline void Modify(int u,int v,int r){ for (;top[u]!=top[v];u=fat[top[u]]) { if (depth[top[u]]<depth[top[v]]) swap(u,v); Seg.Add(tid[top[u]],tid[u],r); } if (depth[u]>depth[v]) swap(u,v); Seg.Add(tid[u],tid[v],r); } inline bool Check(int mid){ int maxd=0,cnt=0; for (int i=1;i<=m;i++) if (eve[i].dis>mid) { ++cnt; Modify(eve[i].u,eve[i].v,1); maxd=max(maxd,eve[i].dis); } int maxl=0; for (int i=1;i<=n;i++) if (i!=1 && Seg.Query(tid[i])==cnt && Seg.Query(tid[fat[i]])==cnt) maxl=max(maxl,dis[i]-dis[fat[i]]); for (int i=1;i<=m;i++) if (eve[i].dis>mid) Modify(eve[i].u,eve[i].v,-1); return maxd-maxl<=mid; } int maxd=0; inline void Bin() { Seg.Build(n); int L=0,R=maxd,MID; while (L+1<R) if (Check(MID=(L+R)>>1)) R=MID; else L=MID; printf("%d\n",R); } int main() { int iu,iv,iw; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(m); for (int i=1;i<n;i++) read(iu),read(iv),read(iw),add(iu,iv,iw,++inum),add(iv,iu,iw,++inum); dfs(1,0); find(1,0,1); for (int i=1;i<=m;i++) { read(iu),read(iv); eve[i].u=iu; eve[i].v=iv; eve[i].lca=LCA(iu,iv); eve[i].dis=dis[iu]+dis[iv]-2*dis[eve[i].lca]; maxd=max(maxd,eve[i].dis); } Bin(); return 0; }