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

第一行包括两个正整数 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

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

 

Sample Input

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

Sample Output

  1. 11

Hint

将第 1 条航道改造成虫洞: 则三个计划耗时分别为:11,12,11,故需要花费的时间为 12。
将第 2 条航道改造成虫洞: 则三个计划耗时分别为:7,15,11,故需要花费的时间为 15。
将第 3 条航道改造成虫洞: 则三个计划耗时分别为:4,8,11,故需要花费的时间为 11。
将第 4 条航道改造成虫洞: 则三个计划耗时分别为:11,15,5,故需要花费的时间为 15。
将第 5 条航道改造成虫洞: 则三个计划耗时分别为:11,10,6,故需要花费的时间为 11。
故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为 11。

(原题传送门[here])


  首先需要求LCA,把所有询问的求的LCA和出发点,结束点保存下来。

  然后二分答案。判断是否可以把耗时大于它的航线的用时缩短到小于等于二分值。

  这个判定就用差分,先在数组中将LCA的值-2,出发点和结束点的值分别+1,从叶节点向上累加。

  关于判定就找1个所有需要改的航线都覆盖了的边。并且使耗时的最大值要不超过二分值,这样样就行了。否则说明还会有航线的值大于二分值。

  另外注意常数对算法的影响,理论复杂度O(n + m + nlog2L)。(L是树上最长链的长度)

Code

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cctype>
  5. #include<algorithm>
  6. #include<cmath>
  7. #include<map>
  8. #include<set>
  9. #include<queue>
  10. #include<stack>
  11. #include<vector>
  12. using namespace std;
  13. #define smin(a, b) a = min(a, b)
  14. #define smax(a, b) a = max(a, b)
  15. typedef bool boolean;
  16. template<typename T>
  17. inline void readInteger(T& u){
  18. char x;
  19. while(!isdigit((x = getchar())));
  20. for(u = x - ''; isdigit((x = getchar())); u = (u << ) + (u << ) + x - '');
  21. ungetc(x, stdin);
  22. }
  23.  
  24. typedef class Edge{
  25. public:
  26. int end;
  27. int next;
  28. int w;
  29. Edge(const int end = , const int next = , const int w = ):end(end), next(next), w(w){}
  30. }Edge;
  31.  
  32. typedef class MapManager{
  33. public:
  34. int ce;
  35. int* h;
  36. Edge* edge;
  37. MapManager(){}
  38. MapManager(int points, int edges):ce(){
  39. h = new int[(const int)(points + )];
  40. edge = new Edge[(const int)(edges + )];
  41. memset(h, , sizeof(int) * (points + ));
  42. }
  43. inline void addEdge(int from, int end, int w){
  44. edge[++ce] = Edge(end, h[from], w);
  45. h[from] = ce;
  46. }
  47. inline void addDoubleEdge(int from, int end, int w){
  48. addEdge(from, end, w);
  49. addEdge(end, from, w);
  50. }
  51. }MapManager;
  52.  
  53. #define m_begin(g, i) (g).h[(i)]
  54. #define m_end(g, i) (g).edge[(i)].end
  55. #define m_next(g, i) (g).edge[(i)].next
  56. #define m_w(g, i) (g).edge[(i)].w
  57.  
  58. template<typename T>class Matrix{
  59. public:
  60. T *p;
  61. int lines;
  62. int rows;
  63. Matrix():p(NULL){ }
  64. Matrix(int lines, int rows):lines(lines), rows(rows){
  65. p = new T[(lines * rows)];
  66. }
  67. T* operator [](int pos){
  68. return (p + pos * lines);
  69. }
  70. };
  71. #define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows)
  72.  
  73. typedef class union_found{
  74. public:
  75. int *f;
  76. union_found():f(NULL) {}
  77. union_found(int points) {
  78. f = new int[(const int)(points + )];
  79. }
  80. int find(int x) {
  81. if(f[x] != x) return f[x] = find(f[x]);
  82. return f[x];
  83. }
  84. int& operator [](int pos){
  85. return f[pos];
  86. }
  87. }union_found;
  88.  
  89. #define BZ_MAX 19
  90.  
  91. typedef class query{
  92. public:
  93. int from;
  94. int end;
  95. int minv;
  96. int lca;
  97. query(const int from = , const int end = , const int lca = , const int minv = ):from(from), lca(lca), end(end), minv(minv){}
  98. boolean operator <(query another) const {
  99. return this->minv < another.minv;
  100. }
  101.  
  102. }query;
  103.  
  104. boolean operator <(int val, query a){
  105. return val < a.minv;
  106. }
  107. int n, q;
  108. int cq;
  109. int* times;
  110. int* up;
  111. int* dis;
  112. MapManager g;
  113. boolean* visited;
  114. boolean* enable;
  115. query *results;
  116. MapManager mq;
  117. union_found uf;
  118.  
  119. inline void init(){
  120. readInteger(n);
  121. readInteger(q);
  122. g = MapManager(n, * n);
  123. mq = MapManager(n, * q);
  124. for(int i = , a, b, c; i < n; i++){
  125. readInteger(a);
  126. readInteger(b);
  127. readInteger(c);
  128. g.addDoubleEdge(a, b, c);
  129. }
  130. for(int i = , a, b; i <= q; i++){
  131. readInteger(a);
  132. readInteger(b);
  133. mq.addDoubleEdge(a, b, );
  134. }
  135. }
  136.  
  137. void dfs(int node, int last, int distance){
  138. up[node] = last;
  139. dis[node] = distance;
  140. for(int i = m_begin(g, node); i != ; i = m_next(g, i)){
  141. int &e = m_end(g, i);
  142. if(e == last) continue;
  143. dfs(e, node, m_w(g, i) + distance);
  144. }
  145. }
  146.  
  147. inline void init_dfs(){
  148. up = new int[(const int)(n + )];
  149. dis = new int[(const int)(n + )];
  150. uf = union_found(n + );
  151. visited = new boolean[(const int)(n + )];
  152. enable = new boolean[(const int)(q * + )];
  153. memset(up, , sizeof(int) * (n + ));
  154. memset(enable, true, sizeof(boolean) * (q * + ));
  155. memset(visited, false, sizeof(boolean) * (n + ));
  156. dfs(, , );
  157. }
  158.  
  159. int cal_length(int a, int b, int lca){
  160. return dis[a] + dis[b] - (dis[lca] << );
  161. }
  162.  
  163. void tarjan(int node){
  164. uf[node] = node;
  165. visited[node] = true;
  166. for(int i = m_begin(g, node); i != ; i = m_next(g, i)){
  167. int& e = m_end(g, i);
  168. if(!visited[e]){
  169. tarjan(e);
  170. uf[e] = node;
  171. }
  172. }
  173. for(int i = m_begin(mq, node); i != ; i = m_next(mq, i)){
  174. int& e = m_end(mq, i);
  175. if(visited[e] && enable[i]){
  176. int lca = uf.find(e);
  177. results[++cq] = query(node, e, lca, cal_length(node, e, lca));
  178. enable[i] = enable[i + ((i & ) ? () : (-))] = false;
  179. }
  180. }
  181. }
  182.  
  183. boolean update(int node, int limit, int maxer, int minx){
  184. for(int j = m_begin(g, node); j != ; j = m_next(g, j)){
  185. int& e = m_end(g, j);
  186. if(e == up[node]) continue;
  187. if(update(e, limit, maxer, minx)) return true;
  188. times[node] += times[e];
  189. }
  190. if(times[node] == limit){
  191. if(maxer - cal_length(node, up[node], up[node]) <= minx){
  192. return true;
  193. }
  194. }
  195. return false;
  196. }
  197.  
  198. boolean check(int minx){
  199. int counter = ;
  200. int maxer = ;
  201. memset(times, , sizeof(int) * (n + ));
  202. query* it = upper_bound(results + , results + q + , minx);
  203. for(; it != results + q + ; it++){
  204. times[it->from]++;
  205. times[it->end]++;
  206. times[it->lca]++;
  207. counter++;
  208. smax(maxer, it->minv);
  209. }
  210. return update(, counter, maxer, minx);
  211. }
  212.  
  213. inline void solve(){
  214. int l = , r;
  215. results = new query[(const int)(q + )];
  216. tarjan();
  217. delete[] visited;
  218. delete[] uf.f;
  219. times = new int[(const int)(n + )];
  220. sort(results + , results + q + );
  221. r = results[q].minv;
  222. while(l <= r){
  223. int mid = l + ((r - l) >> );
  224. if(check(mid)) r = mid - ;
  225. else l = mid + ;
  226. }
  227. printf("%d", r + );
  228. }
  229.  
  230. int main(){
  231. init();
  232. init_dfs();
  233. solve();
  234. return ;
  235. }

(PS:这道题很神奇,vijos过了,codevs的最后一个点TLE)

vijos 运输计划 - 二分答案 - 差分 - Tarjan的更多相关文章

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

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

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

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

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

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

  4. loj2425 「NOIP2015」运输计划[二分答案+树上差分]

    看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\text{mid}$,然后尝试检验.````` 检验是否存在这样一个边置为0后,全部链长$\le\text{mid}$,其最终目标就是.要让所 ...

  5. 运输计划[二分答案 LCA 树上差分]

    也许更好的阅读体验 \(\mathcal{Description}\) 原题链接 概括一下题意 给一颗有\(n\)个点带边权的树,有\(m\)个询问,每次询问\(u,v\)两点间的权值和,你可以将树中 ...

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

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

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

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

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

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

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

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

随机推荐

  1. First normal formal Second normal form

    https://en.wikipedia.org/wiki/First_normal_form https://en.wikipedia.org/wiki/Second_normal_form A r ...

  2. GP服务中无Tasks

    发布GP服务,之后执行GP服务时,发现无Tasks,如下图所示 正常情况应该如下图 问题原因在于,arcmap与server版本不一致~~ (10.4.1arcmap 与 10.2.2 server) ...

  3. 2018/03/28 每日一个Linux命令 之 mkdir/rmdir

    用于建立空文件夹和删除文件夹 -- 两命令重要参数 -p 递归建立/删除 -- 例如 mkdir -p demo1/demo2/demo3 建立demo3空文件夹,如果demo1/demo2没建立也建 ...

  4. 【Python】详解Python多线程Selenium跨浏览器测试

    前言 在web测试中,不可避免的一个测试就是浏览器兼容性测试,在没有自动化测试前,我们总是苦逼的在一台或多台机器上安装N种浏览器,然后手工在不同的浏览器上验证主业务流程和关键功能模块功能,以检测不同浏 ...

  5. 图片放大_css3

    .flash_little_img{position:relative;}.flash_little_img{width:500px;height:333px;border:none; margin: ...

  6. [svc]ftp协议数据连接的2种模式

    玩明白了以太网2的二层数据格式, ip格式 tcp/udp个时候, 需要玩一玩一些有用的基于这些已上的协议数据了. 如 dhcp ftp等.比较有趣. ftp协议 分控制连接21端口 和数据连接 20 ...

  7. 设置pip的默认源

    Python在导入第三方模块的时候用设置豆瓣源的方法提高效率,每次设置很麻烦,所以通过下面方法设置默认源,这样就可以直接pip install package,而不用指定源了. [global] ti ...

  8. NGINX负载均衡缓存配置

    环境:VMware-Workstation-12-Pro,Windows-10,CentOS-7.5,Xshell5 1 概述 如果我们的架构是前端负载均衡后端WEB集群时,可以开启nginx的缓存功 ...

  9. CentOS6.5安装Twemproxy集群

    Twemproxy,也叫Nutcraker.是一个Twtter开源的一个Redis和Memcache代理服务器. Redis作为一个高效的缓存服务器,非常具有应用价值.但是当使用比较多的时候,就希望可 ...

  10. Linear Regression Using Least Squares Method 代码实现

    1. 原理 2. Octave function theta = leastSquaresMethod(X, y) theta = pinv(X' * X) * X' * y; 3. Python # ...