题
大意:
给定一棵
n
n
个节点的带边权的树, 条树上路径。你能将一条边的边权变成
0
0
,问这 条路径中最长路径的长度最小值是多少。
解
最大值最小,可以想到二分。我们二分 最大值能否
≤ans
≤
a
n
s
对于每条长度(假设为
len
l
e
n
)超过
ans
a
n
s
的边,我们就肯定至少要去掉
len−ans
l
e
n
−
a
n
s
的长度。我们可以记
c[i]
c
[
i
]
为每条边在这种长度超过
ans
a
n
s
的边里出现了几次,然后如果有“都出现,并且去掉能符合要求”的边,就能;反之则不能。
怎样判断“去掉能符合要求”?因为前面说了对于每条超出的边,至少去掉
len−ans
l
e
n
−
a
n
s
,所以我们可以记个最大值然后和这条边的边权比一下就行了。
怎样高效地记录
c[i]
c
[
i
]
呢?可以用数据结构,但这是静态的直接差分就可以了,树上差分了解一下。
代码:(洛谷上能过,YZOJ被卡常了5分。。)
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define R register
#define Maxn 300001
#define LG 20
#define getchar() getchar_unlocked() //本机编译请去掉这个
int n,m;
int first[Maxn],next[Maxn<<1],to[Maxn<<1],cnt;
int fa[Maxn],t[Maxn<<1],dis[Maxn];
template <class RME> inline void read(R RME &x)
{
x=0;R bool f=0;R char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
if(f) f=-x;
}
struct query
{
int u,v,lc,diss;
}q[Maxn];
int dep[Maxn],f[Maxn][22],c[Maxn];
inline void link(R int x,R int y,R int z)
{
next[++cnt]=first[x];
first[x]=cnt;
to[cnt]=y;
t[cnt]=z;
}
void dfs(R int now)
{
for (R int i=first[now];i;i=next[i])
{
if(to[i] != f[now][0])
{
f[to[i]][0] = now;
dep[to[i]] = dep[now] + 1;
dis[to[i]] = dis[now] + t[i];
fa[to[i]] = i;
dfs(to[i]);
}
}
}
void dfs1(R int now)
{
for (R int i=first[now];i;i=next[i])
{
if(to[i] != f[now][0])
{
dfs1(to[i]);
c[now] += c[to[i]];
}
}
}
inline int lca(R int x,R int y)
{
if(dep[x] > dep[y]) swap(x,y);
R int tmp=dep[y]-dep[x];
for (R int i=0;i<LG && (1<<i) <= tmp;++i)(tmp&(1<<i)) ? y=f[y][i] : 0;
for (R int i=LG-1;i>=0;--i)
(f[x][i]^f[y][i]) ? x=f[x][i],y=f[y][i] : 0;
return (x^y) ? f[x][0] : x;
}
inline bool check(R int ans)
{
R int tot=0,ned=0;
memset(c,0,sizeof c);
for (R int i=1;i<=m;++i)
{
if(q[i].diss > ans)
{
++tot;
c[q[i].u] ++;
c[q[i].v] ++;
c[q[i].lc] -=2;
ned=max(ned,q[i].diss-ans);
}
}
dfs1(1);
for (R int i=2;i<=n;++i)
if(c[i] == tot && t[fa[i]] >= ned) return 1;
return 0;
}
int main()
{
R int l=-1,r=0;
read(n);read(m);
for (R int i=1,a,b,w;i<n;++i)
{
read(a),read(b),read(w);
link(a,b,w); link(b,a,w);
}
dfs(1);
for (R int i=1;i<=LG;++i)
for (R int j=1;j<=n;++j)
f[j][i]=f[f[j][i-1]][i-1];
for (R int i=1;i<=m;++i)
{
read(q[i].u),read(q[i].v);
q[i].lc=lca(q[i].u,q[i].v);
q[i].diss = dis[q[i].u]+dis[q[i].v]-(dis[q[i].lc]<<1);
r=max(q[i].diss,r);
}
l=r-1001;
while(r-l!=1)
{
R int mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid;
}
printf("%d",r);
return 0;
}