题目描述

公元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. Postman系列三:Postman中post接口实战(上传文件、json请求)

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

  2. Apache新的URL路由重写规则

    在根目录下新建一个 .htaccess 后缀文件,将下面代码放进去即可 <IfModule mod_rewrite.c> Options +FollowSymlinks -Multivie ...

  3. git pull时 git cannot lock ref XXXXXX (unable to update local ref)错误解决方案

    git pull :  git cannot lock ref    XXXXXX (unable to update local ref) pull代码的时候出现的错误,导致代码拉不下来. 看了一下 ...

  4. LeetCode 556. 下一个更大元素 III(Next Greater Element III)

    556. 下一个更大元素 III 556. Next Greater Element III 题目描述 给定一个 32 位正整数 n,你需要找到最小的 32 位整数,其与 n 中存在的位数完全相同,并 ...

  5. Java/C++ 学习资源推荐

    列举一下我所知道的一些学习资源,希望能对大家有所帮助 Java学习资源资源: 1.尚学堂 Java300集 链接:https://study.163.com/course/introduction.h ...

  6. MapReduce面试题

    什么是mapreduce Mapreduce是一个分布式运算程序的编程框架,是用户开发“基于hadoop的数据分析应用”的核心框架.容错高,扩展好,适合pB数据处理 MapReduce 执行过程分析 ...

  7. Qt 自定义QTabWidget

    思路: QTabWidget的特点:点击不同的选项卡显示不同的窗口.可以将QTabWidget分成两部分: (1).选项卡:点击时要知道点击的是哪个选项.则需要将选项卡和窗口的信息存起来,点击时去这个 ...

  8. 链表习题(8)-寻找单链表中数据域大小为k的结点,并与前一结点交换,如果前一结点存在的情况下

    /*寻找单链表中数据域大小为k的结点,并与前一结点交换,如果前一结点存在的情况下*/ /* 算法思想:定义两个指针,pre指向前驱结点,p指向当前结点,当p->data == k的时候,交换 p ...

  9. 文件和异常——python从编程入门到实践

    从文件中读取数据 1. 读取整个文件 要读取文件,首先来创建一个文件: 然后打开并读取这个文件,再将其内容显示到屏幕上: file_reader.py with open('pi_digits.txt ...

  10. STM32F030-UART1_DMA使用提示

    STM32F030-UART1_DMA使用提示 前言: 今天把STM32F030C8T6的串口DMA学习了一下,为了加快各位研发人员的开发进度,避免浪费大量的时间在硬件平台上,写出个人代码调试的经验. ...