<h1>题目描述</h1>
L 国有 n
个星球,还有 n-1
条双向航道,每条航道建立在两个星球之间,这 n-1
条航道连通了 L
国的所有星球。
小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui
号星球沿最快的宇航路径飞行到 vi
号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j
,任意飞船驶过它所花费的时间为 tj
,并且任意两艘飞船之 间不会产生任何干扰。
为了鼓励科技创新,L
国国王同意小 P 的物流公司参与 L
国的航道建设,即允许小 P
把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m
个运输计划。在虫洞建设完成后, 这 m
个运输计划会同时开始,所有飞船一起出发。当这 m
个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
<h1>数据范围</h1>
<h1>解题报告</h1>
题意:给定一棵有n
个节点的树(带有边权),再给定m
条树中的路径。允许将一条树边的权改为0
,并使得这些路径的最长距离最小。输出该修改方案中这些路径中最长的一条。
注意最长的路径最小
,我们就想到了二分答案。
那么怎么检查答案呢?
首先,我们要二分这些路径中的最长路径,设为k
如果有某一路径的距离大于k,那么我们显然就要修改这个路径中的边。就把这些路径标记起来,然后找一条都覆盖的边。如果有某一条边能满足边权值权值 >= 最长路径-k
,那么这个答案k是可行的。
那么怎么要找出来这些覆盖的边呢?
当树退化为一条链时,当然是差分好了。
对于我们的路径i,设起点a[i]
和b[i]
,l[i] = LCA(a[i],b[i])
那么我们就可以让差分数组f[a[i]]++
,f[b[i]]++
,f[l[i]] -= 2
那么最后,数据中提到了注意常数因子的影响
那么我们要注意以下几点:
- 尽量使用快读
- 用Vector的同学改为邻接表或前向星
- 缩小二分范围
Tarjan
好像更快(我没试过)
<h1>代码</h1>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
const int MAXN = 300000 + 5;
const int logN = 24;
inline void Read(int &x){
x = 0;
int flag = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x << 3) + (x << 1) + ch - '0';
ch = getchar();
}
x *= flag;
}
struct Edge{
int to,w,next;
}e[MAXN * 2];
int Max = 0;
int head[MAXN],cnt;
int N,M;
int fMAXN,deep[MAXN],dist[MAXN],topre[MAXN],p[MAXN];
inline void add(int u,int v,int w){
e[cnt] = Edge{v,w,head[u]};
head[u] = cnt++;
e[cnt] = Edge{u,w,head[v]};
head[v] = cnt++;
}
void dfs(int v,int fa){
p[++cnt] = v;
for(int i = 1;i < logN;i++){
fv = ff[v][i-1];
if(!fv) break;
}
for(int i = head[v];i;i = e[i].next){
if(e[i].to != fa){
dist[e[i].to] = dist[v] + e[i].w;
deep[e[i].to] = deep[v] + 1;
f[e[i].to][0] = v;
topre[e[i].to] = e[i].w;
dfs(e[i].to,v);
}
}
}
int lca(int x,int y){
if(deep[x] > deep[y])
std::swap(x,y);
for(int i = logN-1;i >= 0;i--)
if(deep[x] <= deepf[y])
y = fy;
for(int i = logN-1;i >= 0;i--){
if(fx != fy){
x = fx;
y = fy;
}
}
if(x != y) x = fx;
return x;
}
int a[MAXN],b[MAXN],l[MAXN],d[MAXN],cf[MAXN];
bool checker(int k){
memset(cf,0,sizeof(cf));
cnt = 0;
for(int i = 1;i <= M;i++){
if(d[i] > k){
cf[a[i]]++;
cf[b[i]]++;
cf[l[i]]-=2;
cnt++;
}
}
for(int i = N;i >= 1;i--){
cf[f[p[i]][0]] += cf[p[i]];
if(topre[p[i]] >= Max - k && cf[p[i]] == cnt) return true;
}
return false;
}
int Binary_Search(int L,int R){
int mid;
while(L < R){
mid = (L + R) >> 1;
if(checker(mid))
R = mid;
else L = mid + 1;
}
return L;
}
int main(){
Read(N);Read(M);
int Max1 = 0;
for(int u,v,w,i = 1;i < N;i++){
Read(u);Read(v);Read(w);
add(u,v,w);
Max1 = std::max(w,Max1);
}
cnt = 0;
deep[1] = 1;deep[0] = -1;
dfs(1,0);
for(int i = 1;i <= M;i++){
Read(a[i]);Read(b[i]);
l[i] = lca(a[i],b[i]);
d[i] = dist[a[i]] + dist[b[i]] - (dist[l[i]] << 1);
Max = std::max(Max,d[i]);
}
int ans = Binary_Search(Max - Max1, Max + 1);
printf("%dn",ans);
return 0;
}