Luogu P2680 运输计划(二分+树上差分)
题意
题目背景
公元\(2044\)年,人类进入了宇宙纪元。
题目描述
公元\(2044\)年,人类进入了宇宙纪元。
\(L\)国有\(n\)个星球,还有\(n-1\)条双向航道,每条航道建立在两个星球之间,这\(n-1\)条航道连通了\(L\)国的所有星球。
小\(P\)掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从\(u_i\)号星球沿最快的宇航路径飞行到\(v_i\)号星球去。显然,飞船驶过一条航道是需要时间的,对于航道\(j\),任意飞船驶过它所花费的时间为\(t_j\),并且任意两艘飞船之间不会产生任何干扰。
为了鼓励科技创新,\(L\)国国王同意小\(P\)的物流公司参与\(L\)国的航道建设,即允许小\(P\)把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小\(P\)的物流公司就预接了\(m\)个运输计划。在虫洞建设完成后,这\(m\)个运输计划会同时开始,所有飞船一起出发。当这\(m\)个运输计划都完成时,小\(P\)的物流公司的阶段性工作就完成了。
如果小\(P\)可以自由选择将哪一条航道改造成虫洞,试求出小\(P\)的物流公司完成阶段性工作所需要的最短时间是多少?
输入输出格式
输入格式:
第一行包括两个正整数\(n, m\),表示\(L\)国中星球的数量及小\(P\)公司预接的运输计划的数量,星球从\(1\)到\(n\)编号。
接下来\(n-1\)行描述航道的建设情况,其中第\(i\)行包含三个整数\(a_i,b_i\)和\(t_i\),表示第\(i\)条双向航道修建在\(a_i\)与\(b_i\)两个星球之间,任意飞船驶过它所花费的时间为\(t_i\)。数据保证\(1 \leq a_i,b_i \leq n\)且\(0 \leq t_i \leq 1000\)。
接下来\(m\)行描述运输计划的情况,其中第\(j\)行包含两个正整数\(u_j\)和\(v_j\),表示第\(j\)个运输计划是从\(u_j\)号星球飞往\(v_j\)号星球。数据保证\(1 \leq u_i,v_i \leq n\)。
输出格式:
一个整数,表示小\(P\)的物流公司完成阶段性工作所需要的最短时间。
输入输出样例
输入样例:
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
输出样例:
11
说明
所有测试数据的范围和特点如下表所示

思路
树上差分板子题,要不你试试? --logeadd
过了一个月终于把它试出来了...
首先对于答案我们来二分,二分的左区间为\(0\)(当然,最优的左区间并不是\(0\)),有区间为最长的运输计划的长度。
运输区间的长度可以用\(O( \log ^2 n)\)的树链剖分或者\(O( \log n)\)的倍增算法(按照这题的数据强度的话后者显然更可过),可是我们如何判定二分出的答案是否可行呢?
首先处理出长度超过二分答案的边的数量\(sum\),然后从根跑一边\(dfs\),统计每个结点下的每一子树中有多少点在计划中会走到该子树的根结点。如果该值为\(sum\),则用这条边更新最大边权,最后直接看最长计划长度减去最大边权是否小于二分答案即可。
现在又有问题了:如何快速统计呢?这就需要树上差分了。对于每一个计划我们把它看成两个部分:从\(u\)到\(LCA(u,v)\)和从\(LCA(u,v)\)到\(v\),我们再不妨把所有分出的部分都看成向上运输的计划,即把它看成这样的两部分:从\(u\)到\(LCA(u,v)\)和从\(v\)到\(LCA(u,v)\)。然后在树上统计每一结点作为计划开头的次数,记为正数;统计每一结点作为结尾的次数,记为负数。
那么按照上面\(dfs\)的思路,我们就可以这么写:
int dfs2(int now)//先看下面那个函数
{
int re=0;//该结点信息
for(register int i=top[now];i;i=nex[i])
{
if(to[i]==fa[now][0]) continue;
int lzq=dfs2(to[i]);//该结点下的子树信息,
re+=lzq;
if(lzq==sum&&len[i]>tmp) tmp=len[i];//如果刚好有sum条边,更新答案
}
return re+js[now];
}
inline bool check(int now)//二分出的答案为now
{
memset(js,0,sizeof js);//结点作为计划开头的次数计数
tmp=-0x3f3f3f3f,sum=0;//sum记录需要减少时间的计划数量,tmp记录有sum条边同时经过的边的最大长度
for(register int i=0;i<m;i++) if(tim[i]>now) sum++,js[u[i]]++,js[v[i]]++,js[st[i]]-=2;//计数统计
dfs2(1);//开始dfs
return max_time-tmp<=now;//判断最大时间的一个计划的时间是否可减少至now
}
AC代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+5;
int n,m,u[MAXN],v[MAXN],st[MAXN],tim[MAXN];
int cnt,top[MAXN],to[MAXN<<1],len[MAXN<<1],nex[MAXN<<1];
int dep[MAXN],dis[MAXN],fa[MAXN][20];
int L,R,ans,max_time,tmp,sum,js[MAXN];
inline int read()
{
int re=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
void dfs1(int now)
{
for(register int i=1;i<=19;i++) fa[now][i]=fa[fa[now][i-1]][i-1];
for(register int i=top[now];i;i=nex[i])
{
if(to[i]==fa[now][0]) continue;
dis[to[i]]=dis[now]+len[i],dep[to[i]]=dep[now]+1,fa[to[i]][0]=now;
dfs1(to[i]);
}
}
int dfs2(int now)
{
int re=0;
for(register int i=top[now];i;i=nex[i])
{
if(to[i]==fa[now][0]) continue;
int lzq=dfs2(to[i]);
re+=lzq;
if(lzq==sum&&len[i]>tmp) tmp=len[i];
}
return re+js[now];
}
inline int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(register int i=19;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if(x==y) return x;
for(register int i=19;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
inline bool check(int now)
{
memset(js,0,sizeof js);
tmp=-0x3f3f3f3f,sum=0;
for(register int i=0;i<m;i++) if(tim[i]>now) sum++,js[u[i]]++,js[v[i]]++,js[st[i]]-=2;
dfs2(1);
return max_time-tmp<=now;
}
int main()
{
n=read(),m=read();
for(register int i=0;i<n-1;i++)
{
int x=read(),y=read(),z=read();
to[++cnt]=y,len[cnt]=z,nex[cnt]=top[x],top[x]=cnt;
to[++cnt]=x,len[cnt]=z,nex[cnt]=top[y],top[y]=cnt;
}
dep[1]=1;
dfs1(1);
for(register int i=0;i<m;i++)
{
u[i]=read(),v[i]=read(),st[i]=LCA(u[i],v[i]);
tim[i]=dis[u[i]]-dis[st[i]]+dis[v[i]]-dis[st[i]];
if(tim[i]>max_time) max_time=tim[i];
}
L=0,R=max_time;
while(L<=R)
{
int mid=(L+R)>>1;
if(check(mid)) ans=mid,R=mid-1;
else L=mid+1;
}
printf("%d",ans);
return 0;
}
Luogu P2680 运输计划(二分+树上差分)的更多相关文章
- 洛谷 P2680 运输计划-二分+树上差分(边权覆盖)
P2680 运输计划 题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条 ...
- P2680 运输计划 二分+树上差分
又咕咕了几天\(QwQ\) 思路:二分+树上差分 提交:\(\geq5\)次 错因:\(lca\)写错+卡了很久常数(哪位大佬帮我康康,有更好的写法请指出\(QwQ\)) 题解: 我们先将原问题转化为 ...
- [luogu]P2680 运输计划[二分答案][树上差分]
[luogu]P2680 [NOIP2015]运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n ...
- luogu P2680 运输计划 (二分答案+树上差分)
题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间 ...
- 洛谷P2680 运输计划(树上差分+二分)
传送门 考虑树上乱搞 首先这是满足二分性质的,如果在某个时间可以完成工作那么比他更长的时间肯定也能完成工作 然后考虑二分,设当前答案为$mid$,如果有一条链的长度大于$mid$,那么这条链上必须得删 ...
- BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1930 Solved: 1231[Submit][Statu ...
- NOIP2015Day2T3运输计划(二分+树上差分)
做了这么多NOIPTG的题,这是唯一 一道一眼秒的T3(有时候T2还不会做QAQ)... 题目大意就不说了QWQ 思路大概是:啊最大值最小化,来个二分.检验mid的话,显然就是用最长路径减去所有边权& ...
- 【Luogu】P2680运输计划(树上差分+二分)
题目链接 总体思路……怎么说呢……是个暴力吧…… 首先用倍增预处理出每条路径的长度. 然后按长度把路径排序. 然后二分答案.对于当前答案mid检验,怎么检验呢? 首先差分把所有长度比mid大的链上除了 ...
- P2680 运输计划[二分+LCA+树上差分]
题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n−1 条航道连通了 LL 国的所有星球. 小 ...
随机推荐
- Python文件操作回顾
with open("D:/Temp/a.txt", mode='w', encoding='utf-8') as f: f.write('hello') with open(&q ...
- [课后作业] 第002讲:用Python设计第一个游戏 | 课后测试题
试题: 0. 什么是BIF? 1. 用课堂上小甲鱼教的方法数一数 Python3 提供了多少个 BIF? 2. 在 Python 看来:'FishC' 和 'fishc' 一样吗? 3. 在小甲鱼看来 ...
- P1006 传纸条 /// DP+滚动数组
题目大意: https://www.luogu.org/problemnew/show/P1006 题解 不难想到 求从起点到终点的两条不同的路 因为只能向右或向下走 所以纸条1和2不可能同时位于同一 ...
- 使用Math.random()函数生成n到m间的随机数字
使用js生成n到m间的随机数字,主要目的是为后期的js生成验证码做准备,Math.random()函数返回0和1之间的伪随机数 讲解: 本文讲解如何使用js生成n到m间的随机数字,主要目的是为后期的j ...
- Python数据格式化
Python有两种格式化字符串的方式,使用%或者使用内置format()函数. 使用%格式化字符串 在Python中使用%来格式化字符串,用法和效果类似于C语言中的%.格式为:%特定的转换类型 %da ...
- swagger请求参数在header中添加token
网友大部分说的是如下配置 参照配置然而没有作用 注掉改红框内的配置,在方法上加如下注释就可以用 @ApiImplicitParams({ @ApiImplicitParam(paramType = & ...
- (转)Lua语言实现简单的多线程模型
转自: https://blog.csdn.net/john_crash/article/details/49489609 lua本身是不支持真正的多线程的,但是lua提供了相应的机制来实现多线程.l ...
- [NOIP2019模拟赛]LuoguP4261白金元首与克劳德斯
题目描述 给出坐标系中n个矩形,类型1的矩形每单位时间向x轴正方向移动1个单位,类型2的矩形向y轴正方向,初始矩形不重叠,一个点被矩形覆盖当且仅当它在矩形内部(不含边界),求$(-\infty ,+\ ...
- 莫烦PyTorch学习笔记(三)——激励函数
1. sigmod函数 函数公式和图表如下图 在sigmod函数中我们可以看到,其输出是在(0,1)这个开区间内,这点很有意思,可以联想到概率,但是严格意义上讲,不要当成概率.sigmod函数 ...
- js去除空格或所有空格
function trim(str) { return str.replace(/(^\s*)|(\s*$)/g, ""); } /***is_global 设置"g&q ...