傳送門:https://www.luogu.org/problemnew/show/P2680
題目主旨:給你一棵帶權樹,給出一些航道的起點和終點,你要經過它們,就要消耗一次最長的總邊長代價。
現請你刪掉一條邊,使得經過的最長樹上路徑最短。
首先,我們可以想到暴力刪邊做法,只不過很暴力...
然後,考慮正解,我們二分最短路徑的長,那麼會有一些不合法的路徑長度大於二分值。
我們把這些不合法的路徑找出來。因爲所有路徑都不合法,所以,所有路徑都必須刪掉同一條邊,如果他們沒有相同邊,那麼一定不滿足二分條件。這一條相同邊應該找長度最大的相同邊,使得答案最小顯然。
因爲我們要找到所有不合法的條路徑的相同邊 -> 這條邊被經過次
所以記錄邊被經過的次數 -> 樹上差分!!!在的時候直接找到可行邊中最大值
驗證:最長路徑 - 最大長度相同邊 ? 二分值
注意:不可以用 總和 - 總和,因爲
(可能由於某些較短路徑使得總和滿足條件,但最長路徑並不滿足條件,使得答案變小)
->luogu25pts
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define LL long long
#define N 300006
#define MB 600006
#define M 300006
using namespace std;
inline int wread(){
char c(getchar ());int wans(0),flag(1);
while (c<'0' || c>'9'){if (c=='-') flag=-1;c=getchar ();}
while (c>='0' && c<='9'){wans=wans*10+c-'0';c=getchar ();}
return wans*=flag;
}
inline void OUT (int x){
if (x>9) OUT(x/10);
putchar (x%10+'0');
}
int n,m;
int K,hed[N];
struct node {int v,w,nxt;}e[MB];
void ad (int u,int v,int w){
e[++K]=(node){v,w,hed[u]};hed[u]=K;
}
int p[N][20];
int dep[N];
int sav[N];//每個點所代表的那條邊的長度
int dis[N];//與根節點的距離
void dfs (int x,int fa,int wx){
sav[x]=wx;
p[x][0]=fa;
for (int i(1);i<=19;++i) p[x][i]=p[p[x][i-1]][i-1];
for (int i(hed[x]);i!=-1;i=e[i].nxt){
int v(e[i].v);
if (v==fa) continue;
dep[v]=dep[x]+1;
dis[v]=dis[x]+e[i].w;
dfs (v,x,e[i].w);
}
return ;
}
int lca (int a,int b){
if (dep[a]>dep[b]) swap (a,b);
for (int i(19);i>=0;--i)
if (dep[a]<=dep[p[b][i]]) b=p[b][i];
if (a==b) return a;
for (int i(19);i>=0;--i){
if (p[a][i] == p[b][i]) continue;
a=p[a][i]; b=p[b][i];
}
return p[a][0];
}
//樹上差分
int ans[N],nd,Jian;
void getans (int x,int fa){
for (int i(hed[x]);i!=-1;i=e[i].nxt){
int v(e[i].v);
if (v==fa) continue;
getans (v,x);
ans[x]+=ans[v];
}
//因爲差分的每條航道都不滿足最短時間,所以每條航道都需要減去一條邊
if (ans[x]==nd) Jian=max (Jian,sav[x]);
return ;
}
struct node2{int u,v,w;}b[M];
bool e666 (node2 x,node2 y){
return x.w<y.w;
}
bool jud (int mid){
memset (ans,0,sizeof ans);
Jian=0;
LL sum(0);
nd=0;
for (int i(m);i>=1;--i){
if (b[i].w<=mid) break;
++nd;
sum+=b[i].w;
int u(b[i].u),v(b[i].v);
int lca_uv(lca(u,v));
ans[u]++;ans[v]++;ans[lca_uv]-=2;
}
if (nd) getans(1,0);
else return true;
if ( b[m].w-Jian <= mid ) return true;
return false;
}
int main (){
memset (hed,-1,sizeof hed);
n=wread();m=wread();
for (int i(1);i<n;++i){
int u(wread()),v(wread()),w(wread());
ad (u,v,w);ad (v,u,w);
}
dep[1]=1;
dis[1]=0;
dfs (1,0,0);
for (int i(1);i<=m;++i){
int u(wread()),v(wread());
int w(dis[u]+dis[v]-(dis[lca(u,v)]<<1));
b[i]=(node2){u,v,w};
}
sort (b+1,b+m+1,e666);
int l(0),r(b[m].w);
int pr=0;
while (l<=r){
int mid(l+r>>1);
if (jud(mid)) pr=mid,r=mid-1;
else l=mid+1;
}
OUT(pr);
return 0;
}