题目背景

公元 2044 年,人类进入了宇宙纪元。

题目描述

L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。

小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物

流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。

为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。

如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?

输入输出格式

输入格式:

输入文件名为 transport.in。

第一行包括两个正整数 n、m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。

接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai, bi 和 ti,表示第

i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。

接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j个 运输计划是从 uj 号星球飞往 vj 号星球。

输出格式:

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

输入输出样例

输入样例#1:

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

输出样例#1:

11

说明

所有测试数据的范围和特点如下表所示

请注意常数因子带来的程序效率上的影响。

好烦呐。。。

让我们一步一步对这道难题深入分析。

1.整棵树在整个过程中改变的只有1条边的权值,其他边与树的结构都没变化,这是很重要的;

2.我们要在很短的时间内要知道这棵树中任意两点间的距离——那么我们就要选择比较优秀的算法了。由于n,m很大,所以我们能选的较为不错的,一个是用LCA来解,另一个就是用树链剖分(我个人认为树链剖分写起来更快,而且更容易查错);

3.我们必定要将m条路径中,起点终点的LCA求出,作为中转站,便于解题;

4.仔细读题目,任务是让我们求最小的最大值,那么我们自然而然会想到二分;

5.假设我们用树链剖分先将m条路线两点距离等需要的量预处理出来,需要mlogn的时间,而二分又是log级别的,所以主要考虑的还要放在二分的check上面;

6.check怎么来?不慌,按照题目中要求的。当然,不能枚举每条边再判断,否则这样的复杂度已经到了nlog(R-L),意味着判断的过程要在log级别以下,这是完全不可能的(你还要枚举路径呢(m条))。那怎么办?对于这题,check成功的条件更容易判断。怎样算check成功?假设,当前二分的最大值为high,如果m条路径中dis大于high的都记录下来(可以之前就排趟序),假设有cnt条,然后,我们要找一条边,将这条边权值变为0后,要达到m条路径的dis都小于等于high的目的,说明这cnt条“超标”路径必定经过这条边,并且dis[当前路径]-w[当前边]<=high,这样才行;

7.那怎么记录每条边被经过的次数?首先,我们会有一个暴力的想法(真的暴力),如果一条路径(x,y)“超标”,那么将x-->LCA(x,y)和y-->LCA(x,y)经过的边都加上1个经过次数。但是这样实在太慢(只有80分,算不错了),毕竟如果出现链状,时间就退化成线性的了(而且这个链也非可以剖分的树链)。那么怎么优化?我们想到了差分的方法(我真心没想到)。像上面这个例子,就把f[x]++,f[y]++,f[LCA(x,y)]-=2,其中f[i]表示的是从节点i到其父节点的次数(1当然没有),我们可以用DFS累加的方式求出所有边经过的次数。这样,check这个过程的复杂度就降到了O(n)左右,不虚了;

8.当然这种题目肯定都要卡常的,在评测时我加了一句话,出现了神奇的一幕。。。我先用第一种方法(步骤7里),在check开头加了一句if (a[1].dis>high+1000) return 0;(其中a数组按关键字dis从大到小排序),结果就A了!在第二种方法写上同样的东西,跑得反而没有第一种快,还TLE了1个点。。。[yun]蒽哼哼,我想,这也许就是“神剪枝”的威力吧。。。orz ○| ̄|_

下面给出两份代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #define Me(Arr) memset(Arr,0,sizeof Arr);
 6 using namespace std;
 7 const int maxn=300005,maxe=600005;
 8 int n,m,L,R,mid,ans;
 9 int lnk[maxn],nxt[maxe],son[maxe],w[maxe],id[maxe],wsin[maxn],pointto[maxn],tot;
10 int size[maxn],fa[maxn],dep[maxn],gonxt[maxn],top[maxn];
11 int bel[maxn],wei[maxn],wtofa[maxn],cnt;
12 int f[maxn];
13 struct data{
14     int x,y,dis,LCA;
15     bool operator < (const data &u) const {return dis>u.dis;}
16 }a[maxn];
17 int read(){
18     int x=0; char ch=getchar();
19     while (ch<'0'||ch>'9') ch=getchar();
20     while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
21     return x;
22 }
23 void INIT(){
24     tot=cnt=0;
25     Me(lnk); Me(nxt); Me(son); Me(w); Me(id); Me(wsin); Me(wtofa); Me(pointto);
26     Me(size); Me(fa); Me(dep); Me(gonxt); Me(top); Me(wei); Me(bel);
27     top[1]=cnt=bel[1]=1,L=0,R=-1;
28 }
29 void add(int i,int x,int y,int z){
30     nxt[++tot]=lnk[x],son[tot]=y,w[tot]=z,id[tot]=i,lnk[x]=tot;
31 }
32 void DFS_1(int x,int u,int layer){
33     size[x]=1,fa[x]=u,dep[x]=layer;
34     for (int j=lnk[x]; j; j=nxt[j]) if (son[j]!=u){
35         DFS_1(son[j],x,layer+1); size[x]+=size[son[j]],wtofa[son[j]]=w[j],pointto[son[j]]=id[j];
36         if (size[gonxt[x]]<size[son[j]]) gonxt[x]=son[j],wei[x]=w[j];
37     }
38 }
39 void DFS_2(int x){
40     if (gonxt[x]) top[gonxt[x]]=top[x],bel[gonxt[x]]=bel[x],DFS_2(gonxt[x]),wei[x]+=wei[gonxt[x]];
41     for (int j=lnk[x]; j; j=nxt[j]) if (son[j]!=fa[x]&&son[j]!=gonxt[x]) top[son[j]]=son[j],bel[son[j]]=++cnt,DFS_2(son[j]);
42 }
43 void prepare(){
44     DFS_1(1,0,1); DFS_2(1);
45 }
46 int abso(int x){return x>0?x:-x;}
47 int get(int i,int x,int y){
48     int ret=0;
49     while (bel[x]!=bel[y])
50         if (dep[top[x]]>dep[top[y]]) ret+=wei[top[x]]-wei[x]+wtofa[top[x]],x=fa[top[x]];
51         else ret+=wei[top[y]]-wei[y]+wtofa[top[y]],y=fa[top[y]];
52     ret+=abso(wei[x]-wei[y]);
53     a[i].LCA=dep[x]<dep[y]?x:y;
54     return ret;
55 }
56 void work(int u,int v,int LCA){
57     while (u!=LCA) f[pointto[u]]++,u=fa[u];
58     while (v!=LCA) f[pointto[v]]++,v=fa[v];
59 }
60 bool jug(int high){
61     if (a[1].dis>high+1000) return 0;
62     Me(f); int decneed=a[1].dis-high,cnt=0;
63     for (int i=1; i<=m; i++) if (a[i].dis>high) work(a[i].x,a[i].y,a[i].LCA),cnt++; else break;
64     if (!cnt) return 1;
65     for (int i=1; i<n; i++) if (f[i]==cnt&&wsin[i]>=decneed) return 1;
66     return 0;
67 }
68 int main(){
69     n=read(),m=read(),INIT();
70     for (int i=1; i<n; i++){
71         int x=read(),y=read(),z=read(); add(i,x,y,z),add(i,y,x,z); wsin[i]=z;
72     }
73     prepare();
74     for (int i=1; i<=m; i++) a[i].x=read(),a[i].y=read(),a[i].dis=get(i,a[i].x,a[i].y),R=max(R,a[i].dis);
75     sort(a+1,a+1+m);
76     while (L<=R){
77         mid=(L+R)>>1;
78         if (jug(mid)) ans=mid,R=mid-1; else L=mid+1;
79     }
80     printf("%d",ans);
81     return 0;
82 }

View Code

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #define Me(Arr) memset(Arr,0,sizeof Arr);
 6 using namespace std;
 7 const int maxn=300005,maxe=600005;
 8 int n,m,L,R,mid,ans;
 9 int lnk[maxn],nxt[maxe],son[maxe],w[maxe],tot;
10 int size[maxn],fa[maxn],dep[maxn],gonxt[maxn],top[maxn];
11 int bel[maxn],wei[maxn],wtofa[maxn],cnt;
12 int f[maxn];
13 struct data{
14     int x,y,dis,LCA;
15     bool operator < (const data &u) const {return dis>u.dis;}
16 }a[maxn];
17 int read(){
18     int x=0; char ch=getchar();
19     while (ch<'0'||ch>'9') ch=getchar();
20     while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
21     return x;
22 }
23 void INIT(){
24     tot=cnt=0;
25     Me(lnk); Me(nxt); Me(son); Me(w); Me(wtofa);
26     Me(size); Me(fa); Me(dep); Me(gonxt); Me(top); Me(wei); Me(bel);
27     top[1]=cnt=bel[1]=1,L=0,R=-1;
28 }
29 void add(int i,int x,int y,int z){
30     nxt[++tot]=lnk[x],son[tot]=y,w[tot]=z,lnk[x]=tot;
31 }
32 void DFS_1(int x,int u,int layer){
33     size[x]=1,fa[x]=u,dep[x]=layer;
34     for (int j=lnk[x]; j; j=nxt[j]) if (son[j]!=u){
35         DFS_1(son[j],x,layer+1); size[x]+=size[son[j]],wtofa[son[j]]=w[j];
36         if (size[gonxt[x]]<size[son[j]]) gonxt[x]=son[j],wei[x]=w[j];
37     }
38 }
39 void DFS_2(int x){
40     if (gonxt[x]) top[gonxt[x]]=top[x],bel[gonxt[x]]=bel[x],DFS_2(gonxt[x]),wei[x]+=wei[gonxt[x]];
41     for (int j=lnk[x]; j; j=nxt[j]) if (son[j]!=fa[x]&&son[j]!=gonxt[x]) top[son[j]]=son[j],bel[son[j]]=++cnt,DFS_2(son[j]);
42 }
43 void DFS_3(int x){
44     for (int j=lnk[x]; j; j=nxt[j]) if (son[j]!=fa[x]) DFS_3(son[j]),f[x]+=f[son[j]];
45 }
46 void prepare(){
47     DFS_1(1,0,1); DFS_2(1);
48 }
49 int abso(int x){return x>0?x:-x;}
50 int get(int i,int x,int y){
51     int ret=0;
52     while (bel[x]!=bel[y]){
53         if (dep[top[x]]>dep[top[y]]) ret+=wei[top[x]]-wei[x]+wtofa[top[x]],x=fa[top[x]];
54         else ret+=wei[top[y]]-wei[y]+wtofa[top[y]],y=fa[top[y]];
55     }
56     a[i].LCA=dep[x]<dep[y]?x:y;
57     ret+=abso(wei[x]-wei[y]);
58     return ret;
59 }
60 bool jug(int high){
61     if (a[1].dis>high+1000) return 0;
62     if (a[1].dis<=high) return 1;
63     Me(f); int decneed=a[1].dis-high,cnt=0;
64     for (int i=1; i<=m; i++) if (a[i].dis>high) f[a[i].x]++,f[a[i].y]++,f[a[i].LCA]-=2,cnt++; else break;
65     DFS_3(1);
66     for (int i=2; i<=n; i++) if (f[i]==cnt&&wtofa[i]>=decneed) return 1;
67     return 0;
68 }
69 int main(){
70     n=read(),m=read(),INIT();
71     for (int i=1; i<n; i++){
72         int x=read(),y=read(),z=read(); add(i,x,y,z),add(i,y,x,z);
73     }
74     prepare();
75     for (int i=1; i<=m; i++) a[i].x=read(),a[i].y=read(),a[i].dis=get(i,a[i].x,a[i].y),R=max(R,a[i].dis);
76     sort(a+1,a+1+m);
77     while (L<=R){
78         mid=(L+R)>>1;
79         if (jug(mid)) ans=mid,R=mid-1; else L=mid+1;
80     }
81     printf("%d",ans);
82     return 0;
83 }

View Code

转载于:https://www.cnblogs.com/whc200305/p/7121389.html

[NOIP 2015TG D2T3] 运输计划相关推荐

  1. [NOIP 2015]运输计划-[树上差分+二分答案]-解题报告

    [NOIP 2015]运输计划 题面: A[NOIP2015 Day2]运输计划 时间限制 : 20000 MS 空间限制 : 262144 KB 问题描述 公元 2044 年,人类进入了宇宙纪元. ...

  2. UOJ #150 【NOIP2015】 运输计划

    题目描述 公元 \(2044\) 年,人类进入了宇宙纪元. \(L\) 国有 \(n\) 个星球,还有 \(n-1\) 条双向航道,每条航道建立在两个星球之间,这 \(n-1\) 条航道连通了 \(L ...

  3. 【Bzoj4326】运输计划

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MB Submit: 1091  Solved: 696 [Submit][Stat ...

  4. BZOJ 4326 NOIP2015 运输计划(树上差分+LCA+二分答案)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MB Submit: 1388  Solved: 860 [Submit][Stat ...

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

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

  6. P2680 运输计划

    传送门 十分显然完成工作的时间和航耗时最长的运输计划有关 所以题目意思就是要求最大值最小 所以可以想到二分 把所有大于mid时间的航线打上标记,显然删边只能在所有这些航线的公共路径上 要如何快速打标记 ...

  7. [NOIP2015提高组]运输计划

    题目:BZOJ4326.洛谷P2680.Vijos P1983.UOJ#150.codevs4632.codevs5440. 题目大意:有一棵带权树,有一些运输计划,第i个运输计划从ai到bi,耗时为 ...

  8. cogs2109 [NOIP2015] 运输计划

    cogs2109 [NOIP2015] 运输计划 二分答案+树上差分. STO链剖巨佬们我不会(太虚伪了吧 首先二分一个答案,下界为0,上界为max{路径长度}. 然后判断一个答案是否可行,这里用到树 ...

  9. [luogu2680] 运输计划 (lca+二分+树上差分)

    传送门 Description Input Output 一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间. Sample Input 6 3 1 2 3 1 6 4 3 1 7 4 3 ...

最新文章

  1. Core Java 第三章 Java基本的程序设计结构
  2. .NET西安社区 [拥抱开源,又见 .NET] 活动简报
  3. 计算机网络之数据链路层:11、CSMA/CD协议-随机访问介质访问控制
  4. Hadoop框架:NameNode工作机制详解
  5. python 爬虫应用
  6. 改变权限Linux,Linux chmod改变权限属性命令
  7. 正则表达式中符号的含义(可能不是很全)
  8. MAC自带的lnmp
  9. 全国大学生数学建模竞赛2016A题系泊系统的设计MATLAB程序
  10. 高中数学建模优秀论文_高中数学建模优秀论文
  11. 计算机专业优势及就业前景,女生学习计算机专业的优势及就业前景
  12. 中兴GWH-11 ZXV10 H108B的AD路由器获取超级用户密码
  13. adobe flash player 过期问题
  14. CAD基础+常用快捷(三)
  15. 爬虫内涵段子贴吧内容
  16. DSP28335的SPWM波生成方法
  17. DOCK6.9学习(VII)
  18. 【排序-简单】1528. 重新排列字符串
  19. 吴恩达深度神经网络笔记—人脸识别
  20. python 画任意函数曲线_使用Python画数学函数曲线

热门文章

  1. 新一代态势感知系统发布——北望
  2. DOM系列:DOM树和遍历DOM
  3. 什么是 MaxCompute
  4. php 获取目录分隔符,php目录分隔符DIRECTORY_SEPARATOR
  5. 华为OD机试 - 模拟商场优惠打折
  6. 利用SAH实现kD树快速分割模型实践
  7. javascript事件触发器
  8. 知识付费直播使用https方法 教程
  9. 视觉SLAM前端——ICP
  10. 论文写作-如何提高英语论文写作水平