题目描述

公元20442044 年,人类进入了宇宙纪元。

L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n−1 条航道连通了 LL 国的所有星球。

小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 u_iu**i 号星球沿最快的宇航路径飞行到 v_iv**i 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 jj,任意飞船驶过它所花费的时间为 t_jt**j,并且任意两艘飞船之间不会产生任何干扰。

为了鼓励科技创新, LL 国国王同意小 PP 的物流公司参与 LL 国的航道建设,即允许小PP 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

在虫洞的建设完成前小 P 的物流公司就预接了 mm 个运输计划。在虫洞建设完成后,这 mm 个运输计划会同时开始,所有飞船一起出发。当这 mm 个运输计划都完成时,小 PP 的物流公司的阶段性工作就完成了。

如果小 PP 可以自由选择将哪一条航道改造成虫洞, 试求出小 PP 的物流公司完成阶段性工作所需要的最短时间是多少?

解析

这题还是算比较简单的,暴力也能打满分。暴力一点的,树剖一条条试着删m条路径中的最长路径上的边就完事了。

题意很简单:给定带权树,将树中某条边的权值替换为0,并使替换后的最长路径最短。

看到最小化最大值,首先想到二分答案。首先我们要做一些基本的事情,这种在树上给定一对对起点终点的题目,肯定每对起点终点对应的路径是唯一的,我们先求出这些路径,即求LCA。

现在考虑如何二分,现在我们要解决的问题肯定就是在替换哪一条边、能不能替换的问题上了。显然,如果要使得所有起点终点对应的路径长度小于二分出的值,那么我们只需考虑那些比二分出的值大的路径。我们来考察这些路径,发现由于我们只能替换一条边,那么这条要替换的边就一定得是所有比二分出的值大的路径的公共边,否则至少要替换两条边才能使得当前二分情况成立。

那么如何判断所有比二分出的值大的路径有公共边呢?这里是难点。不难想出解决办法,就是统计所有比二分出的值大的路径的经过的边,做路径覆盖,如果最后某一条边被覆盖的次数与比二分出的值大的路径条数相等的话,这条边就是公共边。为了加快计算速度,我们可以使用树上差分技巧。

又如何判断当前二分情况是否成立呢?首先,如果我们没有找到公共边,那么当前情况一定不成立,其至少需要替换两条边。如果我们找到了一条以上的公共边,贪心的思想,一定是替换这些公共边中最长的那一条使得最长路径最短,而如果我们替换掉这最长的一条后最长路径仍然不满足当前二分出来的值,就不合法。

分析到这里,我们发现我们需要以下信息:

  • 所有起点和终点对应的最长的路径长度
  • 所有起点和终点对应的路径长度
  • 每对起点和终点的LCA
  • 二分时,树上每条边被覆盖的次数

这题也没什么好注意的细节问题,二分写好了就没事。

参考代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define N 300010
#define ri register int
using namespace std;
inline int read()
{
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int n,m,f[31][N],t,dep[N],d[N],c[N];
struct node{
int u,v,lca,dis;
}s[N];
struct rec{
int next,ver,edge;
}g[N<<1];
int head[N],tot,up[N];
inline void add(int x,int y,int val)
{
g[++tot].ver=y,g[tot].edge=val;
g[tot].next=head[x],head[x]=tot;
}
inline void init()
{
queue<int> q;
q.push(1);dep[1]=1;
while(q.size()){
int x=q.front();q.pop();
for(ri i=head[x];i;i=g[i].next){
int y=g[i].ver,z=g[i].edge;
if(dep[y]) continue;
dep[y]=dep[x]+1;
d[y]=d[x]+z,up[y]=z;
f[0][y]=x;
for(ri j=1;j<t;++j)
f[j][y]=f[j-1][f[j-1][y]];
q.push(y);
}
}
}
inline int lca(int x,int y)
{
if(dep[y]>dep[x]) swap(x,y);
for(int j=t;j>=0;--j)
if(dep[f[j][x]]>=dep[y]) x=f[j][x];
if(x==y) return x;
for(int j=t;j>=0;--j)
if(f[j][x]!=f[j][y]) x=f[j][x],y=f[j][y];
return f[0][x];
}
inline void dfs(int x,int fa)
{
for(ri i=head[x];i;i=g[i].next){
int y=g[i].ver;
if(y==fa) continue;
dfs(y,x);
c[x]+=c[y];
}
}
inline bool check(int x)
{
int maxx=0,maxn=0,cnt=0;
memset(c,0,sizeof(c));
for(ri i=1;i<=m;++i)
if(s[i].dis>x){
cnt++;
c[s[i].u]++,c[s[i].v]++;
c[s[i].lca]-=2;
maxx=max(maxx,s[i].dis);
}
if(!cnt) return 1;
dfs(1,-1);
for(ri i=1;i<=n;++i)
if(c[i]==cnt) maxn=max(maxn,up[i]);
return maxx-maxn<=x;
}
int main()
{
int maxx=0;
n=read(),m=read();
t=log2(n)+1;
for(int i=1;i<n;++i){
int u=read(),v=read(),val=read();
add(u,v,val),add(v,u,val);
}
init();
for(ri i=1;i<=m;++i){
int f=read(),t=read();
s[i].u=f,s[i].v=t;
s[i].lca=lca(f,t);
s[i].dis=d[f]+d[t]-d[s[i].lca]*2;
maxx=max(maxx,s[i].dis);
}
int l=0,r=maxx;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%d\n",l);
return 0;
}

P2680 运输计划[二分+LCA+树上差分]的更多相关文章

  1. 洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)

    [题目链接] [思路]: 根据题意可以明显看出,当所有任务都完成时的时间是最终的结果,也就是说本题要求,求出最小的最大值. 那这样的话就暗示了将答案二分,进行check. [check方法]: 如果说 ...

  2. [luogu]P2680 运输计划[二分答案][树上差分]

    [luogu]P2680 [NOIP2015]运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n ...

  3. luogu P2680 运输计划 (二分答案+树上差分)

    题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间 ...

  4. BZOJ 4326: NOIP2015 运输计划(二分,树上差分)

    Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1945  Solved: 1243[Submit][Status][Discuss] Descript ...

  5. loj2425 「NOIP2015」运输计划[二分答案+树上差分]

    看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\text{mid}$,然后尝试检验.````` 检验是否存在这样一个边置为0后,全部链长$\le\text{mid}$,其最终目标就是.要让所 ...

  6. 洛谷 P2680 运输计划-二分+树上差分(边权覆盖)

    P2680 运输计划 题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条 ...

  7. Luogu P2680 运输计划(二分+树上差分)

    P2680 运输计划 题意 题目背景 公元\(2044\)年,人类进入了宇宙纪元. 题目描述 公元\(2044\)年,人类进入了宇宙纪元. \(L\)国有\(n\)个星球,还有\(n-1\)条双向航道 ...

  8. bzoj4326: NOIP2015 运输计划(二分+LCA+树上差分)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4326 题目大意:有一颗含有n个顶点的树,每两个点之间有一个边权,现在有m个运输计划,每个 ...

  9. LOJ2425 NOIP2015 运输计划 【二分+LCA+树上差分】*

    LOJ2425 NOIP2015 运输计划 LINK 题意:给你一颗树,可以将任意一条边的权值变成0,然后求m条路径的长度的最小值 思路: 先二分最后的距离ans,然后我们把路程大于ans的所有路径拿 ...

随机推荐

  1. python:找出两个列表中相同和不同的元素(使用推导式)

    #接口返回值 list1 = ['张三', '李四', '王五', '老二'] #数据库返回值 list2 = ['张三', '李四', '老二', '王七'] a = [x for x in lis ...

  2. Postman系列三:Postman中post接口实战(上传文件、json请求)

    一:接口测试过程中GET请求与POST请求的主要区别 从开发角度我们看get与post的主要区别是:1.Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据:2.Get安全性比Post低 ...

  3. Ubuntu环境下非root用户指定版本Python的安装及虚拟环境virtualenv的使用

    Ubuntu环境下非root用户指定版本Python的安装及虚拟环境virtualenv的使用 参考博客: https://blog.csdn.net/leviopku/article/details ...

  4. 微信小程序之自定义导航栏(可实现动态添加)以及swiper(swiper-item)实现自动切换,导航标题也跟着切换

    <view class="movie-container"> <!-- 导航栏 --> <view > <scroll-view scro ...

  5. chamfer_pcd

    import tensorflow as tf import numpy as np def distance_matrix(array1, array2): """ a ...

  6. 深入浅出JVM(一):运行时数据区域

    程序计数器 线程私有 指向了正在执行的虚拟机字节码指令的地址:如果是本地方法,数值为空 没有 OutOfMemoryError 错误的区域 Java虚拟机栈 线程私有: 生命周期与线程相同: 代表着 ...

  7. python3的 基础

    ]print(list(set(lst))) # 面试题: # a = 10 # b = 20 # a,b = b,a      # 10000% # print(b)  # 10 # print(a ...

  8. drf复习(一)--原生djangoCBV请求生命周期源码分析、drf自定义配置文件、drf请求生命周期dispatch源码分析

    admin后台注册model  一.原生djangoCBV请求生命周期源码分析 原生view的源码路径(django/views/generic/base.py) 1.从urls.py中as_view ...

  9. js将文字填充与canvas画布再转为图片

    需求:封装consul服务的webUI: 原因:展示consul的服务信息时,需要嵌套动画,由于其没有内置的icon,所以将服务name放于图片位: 分析:展示信息时采用了卡片式的服务布局,缩放式的服 ...

  10. sql 分组后重复数据取时间最新的一条记录

    1.取时间最新的记录 不分组有重复(多条CreateTime一样的都是最新记录) select * from test t where pid in ( select PId from Test t ...