4144: [AMPPZ2014]Petrol

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 457  Solved: 170
[Submit][Status][Discuss]

Description

给定一个n个点、m条边的带权无向图,其中有s个点是加油站。
每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油站可以补满。
q次询问,每次给出x,y,b,表示出发点是x,终点是y,油量上限为b,且保证x点和y点都是加油站,请回答能否从x走到y。
 

Input

第一行包含三个正整数n,s,m(2<=s<=n<=200000,1<=m<=200000),表示点数、加油站数和边数。
第二行包含s个互不相同的正整数c[1],c[2],...c[s](1<=c[i]<=n),表示每个加油站。
接下来m行,每行三个正整数u[i],v[i],d[i](1<=u[i],v[i]<=n,u[i]!=v[i],1<=d[i]<=10000),表示u[i]和v[i]之间有一条长度为d[i]的双向边。
接下来一行包含一个正整数q(1<=q<=200000),表示询问数。
接下来q行,每行包含三个正整数x[i],y[i],b[i](1<=x[i],y[i]<=n,x[i]!=y[i],1<=b[i]<=2*10^9),表示一个询问。
 

Output

输出q行。第i行输出第i个询问的答案,如果可行,则输出TAK,否则输出NIE。
 

Sample Input

6 4 5
1 5 2 6
1 3 1
2 3 2
3 4 3
4 5 5
6 4 5
4
1 2 4
2 6 9
1 5 9
6 5 8

Sample Output

TAK
TAK
TAK
NIE

HINT

 

Source

[Submit][Status][Discuss]

分析

为了回答每个询问,我们需要加油站之间的最小生成树。

求最小生成树的方式是:让所有的加油站dis为0,做多源最短路,同时记录距离每个点最近的加油站。然后枚举边,可以得到两个加油站之间的可能最短距离。做Kruskal或Prim即可。

求到最小生成树之后,用倍增法维护路径上的最大权值即可。

代码

  1. #include <cmath>
  2. #include <queue>
  3. #include <cstdio>
  4. #include <cstdlib>
  5. #include <cstring>
  6. #include <iostream>
  7. #include <algorithm>
  8.  
  9. using namespace std;
  10.  
  11. #define N 500005
  12. #define inf 0x3f3f3f3f
  13.  
  14. int n, m, s, c[N];
  15.  
  16. struct edge
  17. {
  18. int x, y, w;
  19.  
  20. edge(void) {};
  21. edge(int _x, int _y, int _w) :
  22. x(_x), y(_y), w(_w) {};
  23.  
  24. friend bool operator < (const edge &a, const edge &b)
  25. {
  26. return a.w < b.w;
  27. }
  28. };
  29.  
  30. struct step
  31. {
  32. int id, dis;
  33.  
  34. step(void) {};
  35. step(int a, int b) :
  36. id(a), dis(b) {};
  37.  
  38. friend bool operator < (const step &a, const step &b)
  39. {
  40. return a.dis > b.dis;
  41. }
  42. };
  43.  
  44. namespace kirito
  45. {
  46. edge e[N]; int edge_cnt = ;
  47.  
  48. int hd[N], to[N], vl[N], nt[N], tot;
  49.  
  50. void addEdge(int x, int y, int w)
  51. {
  52. nt[tot] = hd[x]; to[tot] = y; vl[tot] = w; hd[x] = tot++;
  53. nt[tot] = hd[y]; to[tot] = x; vl[tot] = w; hd[y] = tot++;
  54. }
  55.  
  56. int dis[N], from[N];
  57.  
  58. priority_queue<step> pq;
  59. }
  60.  
  61. namespace masiro
  62. {
  63. edge e[N]; int edge_cnt = ;
  64.  
  65. void pushEdge(int x, int y, int w)
  66. {
  67. e[++edge_cnt] = edge(x, y, w);
  68. }
  69.  
  70. int hd[N], to[N], vl[N], nt[N], tot;
  71.  
  72. void addEdge(int x, int y, int w)
  73. {
  74. nt[tot] = hd[x]; to[tot] = y; vl[tot] = w; hd[x] = tot++;
  75. nt[tot] = hd[y]; to[tot] = x; vl[tot] = w; hd[y] = tot++;
  76. }
  77.  
  78. int fa[N];
  79.  
  80. int find(int u)
  81. {
  82. return fa[u] == u ? u : fa[u] = find(fa[u]);
  83. }
  84.  
  85. int root;
  86.  
  87. int dep[N], fat[N][], mex[N][];
  88.  
  89. void predfs(int u, int f)
  90. {
  91. for (int i = ; i < ; ++i)
  92. {
  93. fat[u][i] = fat[fat[u][i - ]][i - ];
  94. mex[u][i] = max(mex[u][i - ], mex[fat[u][i - ]][i - ]);
  95. }
  96.  
  97. for (int i = hd[u]; ~i; i = nt[i])
  98. if (to[i] != f)
  99. {
  100. dep[to[i]] = dep[u] + ;
  101. mex[to[i]][] = vl[i];
  102. fat[to[i]][] = u;
  103. predfs(to[i], u);
  104. }
  105. }
  106. }
  107.  
  108. void prework1(void)
  109. {
  110. using namespace kirito;
  111.  
  112. memset(dis, inf, sizeof(dis));
  113.  
  114. for (int i = ; i <= s; ++i)
  115. {
  116. dis[c[i]] = ;
  117. from[c[i]] = c[i];
  118. pq.push(step(c[i], ));
  119. }
  120.  
  121. while (!pq.empty())
  122. {
  123. step top = pq.top(); pq.pop();
  124.  
  125. if (dis[top.id] != top.dis)
  126. continue;
  127.  
  128. for (int i = hd[top.id]; ~i; i = nt[i])
  129. if (dis[to[i]] > vl[i] + top.dis)
  130. {
  131. from[to[i]] = from[top.id];
  132. dis[to[i]] = vl[i] + top.dis;
  133. pq.push(step(to[i], dis[to[i]]));
  134. }
  135. }
  136.  
  137. for (int i = ; i <= m; ++i)
  138. if (from[e[i].x] ^ from[e[i].y])
  139. masiro::pushEdge(from[e[i].x], from[e[i].y], dis[e[i].x] + dis[e[i].y] + e[i].w);
  140. }
  141.  
  142. void prework2(void)
  143. {
  144. using namespace masiro;
  145.  
  146. sort(e + , e + + edge_cnt);
  147.  
  148. for (int i = ; i <= n; ++i)
  149. fa[i] = i;
  150.  
  151. for (int i = ; i <= edge_cnt; ++i)
  152. {
  153. int fx = find(e[i].x);
  154. int fy = find(e[i].y);
  155.  
  156. if (fx ^ fy)
  157. {
  158. fa[fx] = fy;
  159. addEdge(e[i].x, e[i].y, e[i].w);
  160. }
  161. }
  162.  
  163. root = n + ;
  164.  
  165. for (int i = ; i <= s; ++i)
  166. if (find(c[i]) == c[i])
  167. addEdge(root, c[i], inf);
  168.  
  169. dep[root] = ;
  170. fat[root][] = root;
  171. memset(mex, , sizeof(mex));
  172.  
  173. predfs(root, -);
  174. }
  175.  
  176. int lca(int x, int y)
  177. {
  178. using namespace masiro;
  179.  
  180. int res = ;
  181.  
  182. if (dep[x] < dep[y])
  183. swap(x, y);
  184.  
  185. for (int i = ; i >= ; --i)
  186. if (dep[fat[x][i]] >= dep[y])
  187. {
  188. res = max(res, mex[x][i]);
  189. x = fat[x][i];
  190. }
  191.  
  192. if (x == y)
  193. return res;
  194.  
  195. for (int i = ; i >= ; --i)
  196. if (fat[x][i] != fat[y][i])
  197. {
  198. res = max(res, mex[x][i]);
  199. res = max(res, mex[y][i]);
  200. x = fat[x][i];
  201. y = fat[y][i];
  202. }
  203.  
  204. res = max(res, mex[x][]);
  205. res = max(res, mex[y][]);
  206.  
  207. return res;
  208. }
  209.  
  210. signed main(void)
  211. {
  212. scanf("%d%d%d", &n, &s, &m);
  213.  
  214. for (int i = ; i <= s; ++i)
  215. scanf("%d", c + i);
  216.  
  217. memset(kirito::hd, -, sizeof(kirito::hd));
  218. memset(masiro::hd, -, sizeof(masiro::hd));
  219.  
  220. for (int i = ; i <= m; ++i)
  221. {
  222. int x, y, w; scanf("%d%d%d", &x, &y, &w);
  223.  
  224. kirito::addEdge(x, y, w);
  225. kirito::e[i] = edge(x, y, w);
  226. }
  227.  
  228. prework1();
  229. prework2();
  230.  
  231. int q; scanf("%d", &q);
  232.  
  233. for (int i = ; i <= q; ++i)
  234. {
  235. int x, y, w; scanf("%d%d%d", &x, &y, &w);
  236.  
  237. int maxCost = lca(x, y);
  238.  
  239. if (w >= maxCost)
  240. puts("TAK");
  241. else
  242. puts("NIE");
  243. }
  244. }

BZOJ_4144.cpp

@Author: YouSiki

BZOJ 4144: [AMPPZ2014]Petrol的更多相关文章

  1. BZOJ.4144.[AMPPZ2014]Petrol(Kruskal重构树)

    BZOJ 看别人代码的时候发现哪一步都很眼熟,突然想起来,就在四个月前我好像看过还给别人讲过?mmp=v= 果然不写写就是容易忘.写了好歹忘了的时候还能复习呢(虽然和看别人的好像也没多少差别?). 首 ...

  2. 4144: [AMPPZ2014]Petrol (多源最短路+最小生成树+启发式合并)

    4144: [AMPPZ2014]Petrol Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 752  Solved: 298[Submit][Sta ...

  3. 【BZOJ】4144: [AMPPZ2014]Petrol

    题意 给定一个\(n\)个点.\(m\)条边的带权无向图,其中有\(s\)个点是加油站.每辆车都有一个油量上限\(b\),即每次行走距离不能超过\(b\),但在加油站可以补满.\(q\)次询问,每次给 ...

  4. [BZOJ 4144] Petrol

    Link: BZOJ 4144 传送门 Solution: 一道不错的图论综合题 因为只询问关键点,因此重点是要求出关键点之间的最短路,以最短路建图 记$nst[i]$为离$i$最近的关键点:可以发现 ...

  5. 【BZOJ4144】[AMPPZ2014]Petrol 最短路+离线+最小生成树

    [BZOJ4144][AMPPZ2014]Petrol Description 给定一个n个点.m条边的带权无向图,其中有s个点是加油站. 每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油 ...

  6. bzoj 4152[AMPPZ2014]The Captain

    bzoj 4152[AMPPZ2014]The Captain 给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用. ...

  7. 循环队列+堆优化dijkstra最短路 BZOJ 4152: [AMPPZ2014]The Captain

    循环队列基础知识 1.循环队列需要几个参数来确定 循环队列需要2个参数,front和rear 2.循环队列各个参数的含义 (1)队列初始化时,front和rear值都为零: (2)当队列不为空时,fr ...

  8. BZOJ 4152: [AMPPZ2014]The Captain( 最短路 )

    先按x排序, 然后只有相邻节点的边才有用, 我们连起来, 再按y排序做相同操作...然后就dijkstra ---------------------------------------------- ...

  9. BZOJ 4143: [AMPPZ2014]The Lawyer( sort )

    水题... 排序搞出每天的会议有哪些, 然后再按照会议的开始时间和结束时间排序, 最晚开始的和最早结束的会议不是同一场而且最晚开始的时间>最早结束的会议就有可能方案 -------------- ...

随机推荐

  1. Nginx虚拟目录alias和root目录

    nginx是通过alias设置虚拟目录,在nginx的配置中,alias目录和root目录是有区别的:1)alias指定的目录是准确的,即location匹配访问的path目录下的文件直接是在alia ...

  2. java工程中的.classpath<转载>

    第一部分:classpath是系统的环境变量,就是说JVM加载类的时候要按这个路径下去找,当然这个路径下可以有jar包,那么就是jar包里所有的class. eclipse build path是ec ...

  3. BZOJ 1588: [HNOI2002]营业额统计

    1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 14396  Solved: 5521[Submit][Sta ...

  4. ListView实现原理

    转载:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android所有常用的原生控件当中,用法最复杂的应该就是ListView了 ...

  5. Cordova - 使用Cordova开发iOS应用实战4(调用摄像头拍照,并编辑)

    使用Cordova可以很方便的通过js代码来使用设备摄像头拍照,只需把camera插件添加进来即可. 一,添加camera插件 首先我们要在“终端”中进入工程所在的目录,然后运行如下命令: 1 cor ...

  6. Cordova - 使用Cordova开发iOS应用实战3(添加Cordova控制台插件)

    Cordova - 使用Cordova开发iOS应用实战3(添加Cordova控制台插件) 前文介绍了通过 Safari 的 Web检查器,可以看到控制台输出的信息.但有时这样调试代码不太方便,如果在 ...

  7. eclipse: workspace出错导致无法启用的解决

    通常我们会在eclipse中创建多个workspace,比如一个用于学习,一个用于工作... ,因为种种原因,时不时会发现eclipse切换workspace后启动失败,提示让你去看workspace ...

  8. 关于base64编码的原理和实现

    在前文 Data URI 应用场景小结 中我们提到了一个概念,叫做 base64编码,今天我们就来聊聊 base64编码,揭开它的神秘面纱. 一句话解释:Base64是一种基于64个可打印字符来表示二 ...

  9. MATLAB调用C程序、调试和LDPC译码

    MATLAB是一个很好用的工具.利用MATLAB脚本进行科学计算也特别方便快捷.但是代码存在较多循环时,MATLAB运行速度极慢.如果不想放弃MATLAB中大量方便使用的库,又希望代码能迅速快捷的运行 ...

  10. Javascript的精华啊【如果以后我看到了或者想到了再继续补吧】

    我不过略有一些讨人喜欢的地方而已,怎么会有什么迷人的魔力呢? 一.语法 JS只有一个数字类型,64位浮点数,所以1和1.0是相同的.为什么这么设计:防止短整型的溢出. 二.对象 1.通常将一个对象的值 ...