题目描述 Description

公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?

输入描述 Input Description

第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。数据保证 1≤ai,bi≤n 且 0≤ti≤1000。接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。数据保证 1≤ui,vi≤n

输出描述 Output Description

输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。

样例输入 Sample Input

6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5

样例输出 Sample Output

11

数据范围及提示 Data Size & Hint

测试点编号 n= m= 约定
1 100 1  
2 100 100 第i条航道连接i号星球与i+1号星球
3 100 100  
4 2000 1
5 1000 1000 第i条航道连接i号星球与i+1号星球
6 2000 2000 第i条航道连接i号星球与i+1号星球
7 3000 3000 第i条航道连接i号星球与i+1号星球
8 1000 1000  
9 2000 2000
10 3000 3000
11 80000 1
12 100000 1
13 70000 70000

第i条航道连接i号星球与i+1号星球

14 80000 80000 第i条航道连接i号星球与i+1号星球
15 90000 90000 第i条航道连接i号星球与i+1号星球
16 100000 100000 第i条航道连接i号星球与i+1号星球
17 80000 80000  
18 90000 90000
19 100000 100000
20 300000 300000

所有数据

    1<=ai,bi,uj,vj<=n,0<=ti<=1000

之前的一些废话:还有一天出国,某年NOIP,由于我对NOIP的题都有心理阴影,所以一直不敢把这些没做的最后一题的坑填上,然而今天还是面对了这道题,并且能很快想出做法还是很开心的。

题解:首先蜜汁想到了二分(我也不知道为什么),二分的套路,判断当前解mid是否可行,如何判断是否可行呢?其实就是查看当前这些航线能否通过删去某一条对应的边使得每条路径和都小于mid即可。对于那些原来路径和就比mid小的航线就可以无视它们,只考虑那些需要进行裁剪的航线,我们现在需要找到一条边,使得所有比mid大的航线都必须经过这条边(要不然那些不过这条边的航线就无法进行剪裁,更不必说当前解可行了)。满足这种条件的边可能有很多,我们根据贪心的思路就选取最大的边,然后用路径和最大的那条航线减去这条边权(如果最大的那条航线都可以的话比他小的肯定都可以),并且判断这个结果与mid的大小关系,如果小于等于mid,那就说明当前解可行。

当然这只是一些想法,具体做法如下:首先我们通过dfs预处理出1到所有点的距离,这样方便后续航线路径和的计算,并把每一条航线进行结构体捆绑,按照路径和进行从小到大的排序。之后开始二分,上界是最大航线的路径和,下界是0,判断当前解是否可行的话用upper_bound在有序的航线中查出比mid大的第一条航线,然后开始考虑这些路径,需要找到一条边过所有航线,这个可以拿树上差分在O(n)时间内完成,最后扫一遍所有的边,判断tag[i]是否等于总航线的数值,并取其中的最大值,然后用路径和最大的那条航线减去这条边权,并且判断这个结果与mid的大小关系,如果小于等于mid,那就说明当前解可行。在树上差分的时候需要求出lca,因为我不会写O(1)求lca的,所以会多一个log,但是我们在预处理所有航线的路径和的过程中就会算出lca的值,所以提前存好即可。复杂度O((n+logm)logn)

二分照样很坑爹,改过N次二分的写法还是觉得不够稳,最后决定放弃,用最原始的写法,毕竟这样保险:

代码:

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
#define mem(a,b) memset(a,b,sizeof(a))
inline int read()
{
int x=,f=;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-;c=getchar();}
while(isdigit(c)){x=x*+c-'';c=getchar();}
return x*f;
}
const int maxn=,maxm=;
int n,m,a,b,c,ce=-,es,top[maxn],first[maxn],deep[maxn],fa[maxn],size[maxn],dis[maxn],ms[maxn],L,R,mid;
int tag[maxn],maxw,w[maxn];
struct Edge
{
int u,v,w,next;
Edge() {}
Edge(int _1,int _2,int _3,int _4) :u(_1),v(_2),w(_3),next(_4) {}
}e[maxn<<];
struct path
{
int u,v,lc,len;
path() {}
path(int _1,int _2,int _3,int _4):u(_1),v(_2),lc(_3),len(_4) {}
bool operator < (const path& s)const {return len<s.len;}
}line[maxm];
void addEdge(int a,int b,int c)
{
e[++ce]=Edge(a,b,c,first[a]);first[a]=ce;
e[++ce]=Edge(b,a,c,first[b]);first[b]=ce;
}
void dfs(int now,int pa)
{
size[now]=;
for(int i=first[now];i!=-;i=e[i].next)
if(e[i].v!=pa)
{
deep[e[i].v]=deep[now]+;
dis[e[i].v]=dis[now]+e[i].w;
w[e[i].v]=e[i].w;
dfs(e[i].v,now);
if(size[ms[now]]<size[e[i].v])ms[now]=e[i].v;
size[now]+=size[e[i].v];
fa[e[i].v]=now;
}
}
void divide(int now,int chain)
{
top[now]=chain;
if(ms[now])divide(ms[now],chain);
for(int i=first[now];i!=-;i=e[i].next)if(e[i].v!=fa[now] && e[i].v!=ms[now])divide(e[i].v,e[i].v);
}
int lca(int a,int b)
{
while(top[a]!=top[b])
{
if(deep[top[a]]<deep[top[b]])swap(a,b);
a=fa[top[a]];
}
return deep[a]<deep[b] ? a : b;
}
void pushup(int now)
{
for(int i=first[now];i!=-;i=e[i].next)
if(fa[now]!=e[i].v)pushup(e[i].v),tag[now]+=tag[e[i].v];
}
bool check(int mid)
{
int maxw=;
path tmp=path(,,,mid);
int pos=upper_bound(line,line+m,tmp)-line;
mem(tag,);
for(int i=pos;i<m;i++)
{
tag[line[i].u]++;tag[line[i].v]++;
tag[line[i].lc]-=;
}
pushup();
for(int i=;i<=n;i++)if(tag[i]==m-pos)maxw=max(maxw,w[i]);
return line[m-].len-maxw<=mid;
}
int main()
{
mem(first,-);
n=read();m=read();
for(int i=;i<n;i++)a=read(),b=read(),c=read(),addEdge(a,b,c);
dfs(,);divide(,);
for(int i=;i<m;i++)
{
a=read();b=read();c=lca(a,b);
line[i]=path(a,b,c,dis[a]+dis[b]-*dis[c]);
}
sort(line,line+m);
L=;R=line[m-].len;
while(R-L>)
{
mid=(L+R)>>;
if(check(mid))R=mid;
else L=mid;
}
if(check(L))printf("%d\n",L);
else printf("%d\n",R);
return ;
}

总结:树上差分真的太好使了!!二分还是老老实实按上面那么写吧。

[CODEVS4632][BZOJ4326]运输计划的更多相关文章

  1. bzoj4326 运输计划

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MB Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n ...

  2. NOIP2015 D2T3 洛谷2680 BZOJ4326 运输计划 解题报告

    前言:个人认为这是历年NOIP中比较简单的最后一题了,因此将自己的思路与大家分享. 题目大意: 给一棵无根树,给出m条路径.允许将树上的一条边的权值改为0.求m条路径长度最大值的最小值.n,m< ...

  3. [BZOJ4326][codevs4632][codevs5440][UOJ#150][NOIP2015]运输计划

    [BZOJ4326][codevs4632][codevs5440][UOJ#150][NOIP2015]运输计划 试题描述 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n− ...

  4. 【bzoj4326】[NOIP2015]运输计划

    题目描述 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该 ...

  5. NOIP2015 运输计划(bzoj4326)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 886  Solved: 574[Submit][Status] ...

  6. [bzoj4326][NOIP2015]运输计划

    Description 公元2044年,人类进入了宇宙纪元. 国有个星球,还有条双向航道,每条航道建立在两个星球之间,这条航道连通了国的所有星球. 小掌管一家物流公司,该公司有很多个运输计划,每个运输 ...

  7. 【BZOJ-4326】运输计划 树链剖分 + 树上差分 + 二分

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 703  Solved: 461[Submit][Status] ...

  8. BZOJ4326或洛谷2680 运输计划

    BZOJ原题链接 洛谷原题链接 用\(LCA\)初始化出所有运输计划的原始时间,因为答案有单调性,所以二分答案,然后考虑检验答案. 很容易想到将所有超出当前二分的答案的运输计划所经过的路径标记,在这些 ...

  9. 【bzoj4326】[NOIP2015]运输计划 二分答案+LCA

    题目描述 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该 ...

随机推荐

  1. 大话OI

    本文将收录一切我认为对我十分有帮助的他人的博文以及我认为有价值的我自己的原创文章. 引言 有人说:程序=算法+数据结构,所以OI=程序=算法+数据结构. 在我看来,这句话的前半句是对的,但后半句则有本 ...

  2. JavaScript对象及初识面向对象

    一.对象 1.1对象是什么 对象是包含相关属性和方法的集合体 1.2什么是面向对象 面向对象仅仅是一个概念或者编程思想 通过一种叫做原型的方式来实现面向对象编程 二.创建对象 2.1自定义对象 2.1 ...

  3. 明解JAVA 第二章答案

    练习2-1 编译错误,无法运行. 练习2-2 package candle1220; class Nightwatch{ public static void main(String[] args) ...

  4. 数据迁移最快方式,多线程并行执行 Sql插入

    前言: 由于系统升级,新开发的系统对数据验证,及数据关联做了很多优化,现需要将原历史版本的数据迁移到新系统中:原数据库大约有 1千多万数据,大约 50个表. 历史数据库命名为:A. 新系统库暂命名为 ...

  5. tsconfig.json配置项详解

    { "compilerOptions": { "allowUnreachableCode": true, // 不报告执行不到的代码错误. "allo ...

  6. 【机器学习】PCA

    目录 PCA 1. PCA最大可分性的思想 2. 基变换(线性变换) 3. 方差 4. 协方差 5. 协方差矩阵 6. 协方差矩阵对角化 7. PCA算法流程 8. PCA算法总结 PCA PCA 就 ...

  7. jetty9部署

    https://blog.51cto.com/5404542/1751702     Jetty 9部署web应用 Jetty相关的文章比较少,不过官方文档挺齐全的.做下记录也是好事. jetty9跟 ...

  8. c# Equal函数 and 运算符'==' (原发布 csdn 2017年10月15日 20:39:26)

    1.==.!=.<.>.<= 和>= 运算符为比较运算符(comparison operator).C#语言规范5.0中文版中比较运算符的描述如下: 2.通用类型系统 3.值类 ...

  9. c# sqlserver 删除大批量数据超时

    我做的项目有个功能需要进行批量删除,删除的数据量有4.5W条数据. 通过下面的sql语句删除这么多数据,直接导致结果超时,无法删除数据. ,,,......) 我查了一些资料,可能找的不全,找到了一个 ...

  10. asp.net发布后其他电脑部署——未能加载文件或程序集 System.Web.Mvc, Version=2.0.0.0, Culture=neutral,

    本机测试及发布使用正常 在项目中添加了引用但相关dll文件未在bin文件夹中 导致发布后部署其他电脑未能加载程序集 网上说要下载相关内容在部署服务器安装 但怕在服务器安装出现其他问题 所以在项目中重新 ...