版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/violinlove/article/details/83246412
传送门:https://www.luogu.org/problemnew/show/P2680
题目主旨:给你一棵带权树,给出一些航道的起点和终点,你要经过它们,就要消耗一次最长的总边长代价。
现请你删掉一条边,使得经过的最长树上路径最短。
首先,我们可以想到暴力删边做法,只不过很暴力...
然后,考虑正解,我们二分最短路径的长,那么会有一些不合法的路径长度大于二分值。
我们把这些不合法的路径找出来。因为所有路径都不合法,所以,所有路径都必须删掉同一条边,如果他们没有相同边,那么一定不满足二分条件。这一条相同边应该找长度最大的相同边,使得答案最小显然。
因为我们要找到所有不合法的条路径的相同边 -> 这条边被经过次
所以记录边被经过的次数 -> 树上差分!!!在的时候直接找到可行边中最大值
验证:最长路径 - 最大长度相同边 ? 二分值
注意:不可以用 总和 - 总和,因为
(可能由于某些较短路径使得总和满足条件,但最长路径并不满足条件,使得答案变小)
扫描二维码关注公众号,回复:
3700845 查看本文章
->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;
}