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 运输计划(二分+树上差分)的更多相关文章

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

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

  2. P2680 运输计划 二分+树上差分

    又咕咕了几天\(QwQ\) 思路:二分+树上差分 提交:\(\geq5\)次 错因:\(lca\)写错+卡了很久常数(哪位大佬帮我康康,有更好的写法请指出\(QwQ\)) 题解: 我们先将原问题转化为 ...

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

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

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

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

  5. 洛谷P2680 运输计划(树上差分+二分)

    传送门 考虑树上乱搞 首先这是满足二分性质的,如果在某个时间可以完成工作那么比他更长的时间肯定也能完成工作 然后考虑二分,设当前答案为$mid$,如果有一条链的长度大于$mid$,那么这条链上必须得删 ...

  6. BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1930  Solved: 1231[Submit][Statu ...

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

    做了这么多NOIPTG的题,这是唯一 一道一眼秒的T3(有时候T2还不会做QAQ)... 题目大意就不说了QWQ 思路大概是:啊最大值最小化,来个二分.检验mid的话,显然就是用最长路径减去所有边权& ...

  8. 【Luogu】P2680运输计划(树上差分+二分)

    题目链接 总体思路……怎么说呢……是个暴力吧…… 首先用倍增预处理出每条路径的长度. 然后按长度把路径排序. 然后二分答案.对于当前答案mid检验,怎么检验呢? 首先差分把所有长度比mid大的链上除了 ...

  9. P2680 运输计划[二分+LCA+树上差分]

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

随机推荐

  1. Ip- Linux必学的60个命令

    1.作用 ip是iproute2软件包里面的一个强大的网络配置工具,它能够替代一些传统的网络管理工具,例如ifconfig.route等,使用权限为超级用户.几乎所有的Linux发行版本都支持该命令. ...

  2. Matlab AlexNet 识别花

    1. 首先,你要又并行计算的工具箱,在插件选项里面找到,安装即可 2. 下载训练的数据集,采用matlab演示的材料即可 https://matlabacademy-content.mathworks ...

  3. Jquery实现图片瀑布流思路-简单版

    目录 Jquery实现图片瀑布流思路-简单版 1.预备 2.开始 1.声明 2.主体 3.窗体大小改变事件 Jquery实现图片瀑布流思路-简单版 注意:本篇文章基于知道每张图片的实际尺寸的情况下 特 ...

  4. 前端基础之BOM与DOM操作

    目录 BOM操作 navigator对象 screen对象 history对象 localtion对象 弹出框 计时 setTimeout() clearTimeout() setInterval() ...

  5. 前缀后缀——cf1167E

    想了很久没弄明白,对于边界的情况还是有问题 等题解出了再看看 然后枚举每个后缀r,找到比它小,并且在其左边的前缀l,那么删<=l,r-1的都可以 最后的二分很迷:要多考虑特殊情况:前缀跑到后缀后 ...

  6. DuiLib学习笔记1.编译运行demo

    c++中皮肤问题比较麻烦,MFC自带的太难用.DirectUI界面库就比较强大了,之前像skin++之类的基于DirectUI收费昂贵.DuiLib是基于DirectUI的界面库,可以将用户界面和处理 ...

  7. Android之selector选择器的使用

    1.selector简介 selector中文的意思选择器,在Android中常常用来作组件的背景,实现组件在不同状态下不同的背景颜色或图片的变换.使用十分方便.主要是用来改变ListView和But ...

  8. 通过数据库中的表,使用 MyEclipse2017的反向生成工具-->hibernate反转引擎引擎(MyEclipse2017自带的插件) 来反转生成实体类和对应的映射文件

    通过数据库中的表,使用 MyEclipse2017的反向生成工具-->hibernate反转引擎引擎(MyEclipse2017自带的插件) 来反转生成实体类和对应的映射文件   文章目录 Ja ...

  9. 模板——二分图匹配KM

    具体方法就不介绍了,详见 https://blog.csdn.net/sixdaycoder/article/details/47720471 主要讲一些注意点: 1:不直接将未匹配的y减小是因为要保 ...

  10. nprogress 转

    转载:http://www.xuanfengge.com/front-end-nprogress-and-lightweight-web-progress-bar-nanobar.html 前言 进度 ...