题目描述

公元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. 【OpenCV开发】OpenCV3后IPLimage转换成MAT的问题

    IplImage* img1 = cvCreateImage(cvGetSize(resizeRes), IPL_DEPTH_8U, 1);//创建目标图像 Mat test = img1;  报错 ...

  2. npm创建angular项目

    1.首先保证你本地的 node 环境 是ok的哦. 2.安装 angular-cli    命令  npm install -g @angular/cli.安装完成后,ng version 查看版本, ...

  3. win10 双网卡设置内网和外网同时访问

    当前环境是内网使用固定ip 用有线连接 外网自动获取使用wifi模块连接wifi cmd窗口下运行route print -4 打印路由信息 首先删除 所有0.0.0.0的路由,也就是默认设置 rou ...

  4. 02_四大组件之Activity

    四大组件之Activity 1. 理论概述 1.1 Activity的理解 Servlet的理解回顾 狭义 Servlet是一个interface,我们的Servlet类都必须是此接口的实现类 广义 ...

  5. 宁夏网络赛-F-Moving On

    https://www.cnblogs.com/31415926535x/p/11440395.html 一道简单的Floyd题,,但是是动态加点求多次有限制的最短路,,感觉这个思想很好,,当然可以直 ...

  6. Nmap脚本使用

    Nmap是主机扫描工具,他的图形化界面是Zenmap,分布式框架为Dnamp. Nmap可以完成以下任务: 主机探测 端口扫描 版本检测 系统检测 支持探测脚本的编写 Nmap在实际中应用场合如下: ...

  7. 01-打印Hello World、变量

    一.打印Hello World 下面就是我们写的打印hello world程序 在go语言中://代表单行注释,/**/代表多行注释 //单行注释 /* 多行注释 多行注释 */ package ma ...

  8. proxy_banner

  9. AS3.0绘图API

    AS3.0绘图API: /** * * *-------------------* * | *** 绘图API *** | * *-------------------* * * 编辑修改收录:fen ...

  10. [洛谷U72177]火星人plus

    题目大意:给你一个$1\sim n(n\leqslant 10^5)$的排列,设$a$为它在$1\sim n$的全排列中的排名,求在$1\sim n$的全排列中第$a+m$个排列. 题解:康托展开以及 ...