问题分析

首先不难想到是虚树。建完虚树需要保持节点间原先的距离关系。

然后总距离和最小距离用树形DP求,最大距离用两遍dfs即可。注意统计的时候只对关键点进行统计。

真是麻烦

参考程序

ac的时候是loj上速度最后一页,代码第四长的……

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int Maxn = 1000010;
  4. const long long INF = 1000000000010;
  5. const int MaxLog = 20;
  6. struct edge {
  7. int To, Next;
  8. long long Length;
  9. edge() : To( 0 ), Next( 0 ), Length( 0LL ) {}
  10. edge( int _To, int _Next, long long _Length ) :
  11. To( _To ), Next( _Next ), Length( _Length ) {}
  12. };
  13. int n, q, k, A[ Maxn ], Important[ Maxn ];
  14. int DFa[ Maxn ][ MaxLog ], Deep[ Maxn ], Dfn[ Maxn ], Time;
  15. int Stack[ Maxn ];
  16. int Flag[ Maxn ];
  17. struct graph {
  18. int Start[ Maxn ], Used, State;
  19. edge Edge[ Maxn << 1 ];
  20. graph() {}
  21. inline void Init( int _DYT ) {
  22. State = _DYT;
  23. Used = 0;
  24. return;
  25. }
  26. inline void AddDirectedEdge( int x, int y, long long Len ) {
  27. if( Flag[ x ] != State ) {
  28. Flag[ x ] = State;
  29. Start[ x ] = 0;
  30. }
  31. Edge[ ++Used ] = edge( y, Start[ x ], Len );
  32. Start[ x ] = Used;
  33. return;
  34. }
  35. inline void AddUndirectedEdge( int x, int y, long long Len ) {
  36. AddDirectedEdge( x, y, Len );
  37. AddDirectedEdge( y, x, Len );
  38. return;
  39. }
  40. };
  41. graph Prime, Now;
  42. long long Ans, Max, Min;
  43. int Size[ Maxn ], Id;
  44. void Build( int u, int Fa ) {
  45. Deep[ u ] = Deep[ Fa ] + 1;
  46. Dfn[ u ] = ++Time;
  47. DFa[ u ][ 0 ] = Fa;
  48. for( int i = 1; i < MaxLog; ++i )
  49. DFa[ u ][ i ] = DFa[ DFa[ u ][ i - 1 ] ][ i - 1 ];
  50. for( int t = Prime.Start[ u ]; t; t = Prime.Edge[ t ].Next ) {
  51. int v = Prime.Edge[ t ].To;
  52. if( v == Fa ) continue;
  53. Build( v, u );
  54. }
  55. return;
  56. }
  57. inline bool Cmp( int x, int y ) {
  58. return Dfn[ x ] < Dfn[ y ];
  59. }
  60. int GetLca( int x, int y ) {
  61. if( Deep[ x ] < Deep[ y ] ) swap( x, y );
  62. for( int i = MaxLog - 1; i >= 0; --i )
  63. if( Deep[ DFa[ x ][ i ] ] >= Deep[ y ] )
  64. x = DFa[ x ][ i ];
  65. if( x == y ) return x;
  66. for( int i = MaxLog - 1; i >= 0; --i )
  67. if( DFa[ x ][ i ] != DFa[ y ][ i ] ) {
  68. x = DFa[ x ][ i ];
  69. y = DFa[ y ][ i ];
  70. }
  71. return DFa[ x ][ 0 ];
  72. }
  73. struct info {
  74. long long Min, Sec;
  75. info() : Min( INF ), Sec( INF ) {}
  76. info( long long _Min, long long _Sec ) : Min( _Min ), Sec( _Sec ) {}
  77. inline info operator + ( const long long Other ) const {
  78. return info( Min + Other, Sec + Other );
  79. }
  80. inline info operator + ( const info Other ) const {
  81. return ( Min < Other.Min ) ? info( Min, min( Sec, Other.Min ) ) : info( Other.Min, min( Min, Other.Sec ) ) ;
  82. }
  83. };
  84. info GetMin( int u, int Fa ) {
  85. info Ans = info( INF, INF );
  86. if( Important[ u ] == Now.State ) Ans.Min = 0;
  87. for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
  88. int v = Now.Edge[ t ].To;
  89. if( v == Fa ) continue;
  90. Ans = Ans + ( GetMin( v, u ) + Now.Edge[ t ].Length );
  91. }
  92. Min = min( Min, Ans.Min + Ans.Sec );
  93. return Ans;
  94. }
  95. void GetMax( int u, int Fa, long long Len ) {
  96. if( Len > Max && Important[ u ] == Now.State ) {
  97. Max = Len;
  98. Id = u;
  99. }
  100. for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
  101. int v = Now.Edge[ t ].To;
  102. if( v == Fa ) continue;
  103. GetMax( v, u, Len + Now.Edge[ t ].Length );
  104. }
  105. return;
  106. }
  107. long long GetAns( int u, int Fa ) {
  108. Size[ u ] = 0; long long Sum = 0;
  109. if( Important[ u ] == Now.State ) Size[ u ] = 1;
  110. for( int t = Now.Start[ u ]; t; t = Now.Edge[ t ].Next ) {
  111. int v = Now.Edge[ t ].To;
  112. if( v == Fa ) continue;
  113. long long SS = GetAns( v, u );
  114. Ans += Sum * Size[ v ] + Size[ u ] * ( Now.Edge[ t ].Length * Size[ v ] + SS );
  115. Sum += SS + Now.Edge[ t ].Length * Size[ v ];
  116. Size[ u ] += Size[ v ];
  117. }
  118. return Sum;
  119. }
  120. void Work( int Case ) {
  121. Now.Init( Case );
  122. scanf( "%d", &k );
  123. for( int i = 1; i <= k; ++i ) scanf( "%d", &A[ i ] );
  124. for( int i = 1; i <= k; ++i ) Important[ A[ i ] ] = Case;
  125. sort( A + 1, A + k + 1, Cmp );
  126. Stack[ 0 ] = 1; Stack[ 1 ] = 1;
  127. int Len, Lca;
  128. for( int i = 1; i <= k; ++i ) {
  129. if( i == 1 && A[ 1 ] == 1 ) continue;
  130. if( i > 1 && A[ i ] == A[ i - 1 ] ) continue;
  131. Lca = GetLca( Stack[ Stack[ 0 ] ], A[ i ] );
  132. if( Deep[ Lca ] == Deep[ Stack[ Stack[ 0 ] ] ] )
  133. Stack[ ++Stack[ 0 ] ] = A[ i ];
  134. else {
  135. while( Deep[ Stack[ Stack[ 0 ] - 1 ] ] > Deep[ Lca ] ) {
  136. Len = Deep[ Stack[ Stack[ 0 ] ] ] - Deep[ Stack[ Stack[ 0 ] - 1 ] ];
  137. Now.AddUndirectedEdge( Stack[ Stack[ 0 ] - 1 ], Stack[ Stack[ 0 ] ], Len );
  138. --Stack[ 0 ];
  139. }
  140. if( Deep[ Stack[ Stack[ 0 ] - 1 ] ] == Deep[ Lca ] ) {
  141. Len = Deep[ Stack[ Stack[ 0 ] ] ] - Deep[ Stack[ Stack[ 0 ] - 1 ] ];
  142. Now.AddUndirectedEdge( Stack[ Stack[ 0 ] - 1 ], Stack[ Stack[ 0 ] ], Len );
  143. --Stack[ 0 ];
  144. Stack[ ++Stack[ 0 ] ] = A[ i ];
  145. } else {
  146. Len = Deep[ Stack[ Stack[ 0 ] ] ] - Deep[ Lca ];
  147. Now.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Lca, Len );
  148. --Stack[ 0 ];
  149. Stack[ ++Stack[ 0 ] ] = Lca;
  150. Stack[ ++Stack[ 0 ] ] = A[ i ];
  151. }
  152. }
  153. }
  154. while( Stack[ 0 ] > 1 ) {
  155. Len = Deep[ Stack[ Stack[ 0 ] ] ] - Deep[ Stack[ Stack[ 0 ] - 1 ] ];
  156. Now.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ], Len );
  157. --Stack[ 0 ];
  158. }
  159. Min = INF;
  160. GetMin( 1, 0 );
  161. Max = -1;
  162. GetMax( A[ 1 ], 0, 0 );
  163. Max = -1;
  164. GetMax( Id, 0, 0 );
  165. Ans = 0;
  166. GetAns( 1, 0 );
  167. printf( "%lld %lld %lld\n", Ans, Min, Max );
  168. return;
  169. }
  170. int main() {
  171. scanf( "%d", &n );
  172. for( int i = 1; i < n; ++i ) {
  173. int x, y;
  174. scanf( "%d%d", &x, &y );
  175. Prime.AddUndirectedEdge( x, y, 1 );
  176. }
  177. Build( 1, 0 );
  178. scanf( "%d", &q );
  179. for( int i = 1; i <= q; ++i ) Work( i );
  180. return 0;
  181. }

「HEOI2014」大工程的更多相关文章

  1. 「ZJOI2016」大森林 解题报告

    「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...

  2. LOJ#2230. 「BJOI2014」大融合

    LOJ#2230. 「BJOI2014」大融合 题目描述 小强要在$N$个孤立的星球上建立起一套通信系统.这套通信系统就是连接$N$个点的一个树.这个树的边是一条一条添加上去的. 在某个时刻,一条边的 ...

  3. 【HEOI2014】大工程<虚树>

    虚树 我们每天都用心思索着,这究竟是为了什么呢?我想我也不知道,只是觉得如果人不思考问题就很无聊. 我觉得虚树不是什么数据结构,就是一种技巧或者工具.它能把树中\(k\)个关键点以\(O(klogk) ...

  4. 【BZOJ】【3611】【HEOI2014】大工程

    虚树+树形DP 本题100W的点数……不用虚树真的好吗…… Orz ZYF 我的感悟: dp的过程跟SPOJ 1825 FTOUR2 的做法类似,依次枚举每个子树,从当前子树和之前的部分中各找一条最长 ...

  5. 「HEOI2014」南园满地堆轻絮

    题目链接 戳我 题目出处 菩萨蛮·南园满地堆轻絮                                             温庭筠 南园满地堆轻絮,愁闻一霎清明雨.雨后却斜阳,杏花零落香 ...

  6. @loj - 2092@ 「ZJOI2016」大森林

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Y 家里有一个大森林,里面有 n 棵树,编号从 1 到 n. ...

  7. 【LOJ】#2230. 「BJOI2014」大融合

    题解 我现在真是太特么老年了 一写数据结构就颓废,难受 这题就是用lct维护子树 ???lct怎么维护子树 这样想,我们给每个点记录虚边所在的子树大小,只发生在Access和link的时候 这样的话我 ...

  8. loj2230 「BJOI2014」大融合

    LCT裸题 我LCT学傻了这题明显可以树剖我不会树剖了 本来的siz是Splay上的子树和,并没有什么用. 所以每个点维护虚子树和和子树和 虚子树和即虚边连接的子树和,且只有在access和link操 ...

  9. loj2092 「ZJOI2016」大森林

    ref不是太懂-- #include <algorithm> #include <iostream> #include <cstring> #include < ...

随机推荐

  1. 【spring Boot】spring boot获取资源文件的三种方式【两种情况下】

    首先声明一点,springboot获取资源文件,需要看是 1>从spring boot默认的application.properties资源文件中获取 2>还是从自定义的资源文件中获取 带 ...

  2. kafka运维填坑

    转载自:https://www.jianshu.com/p/d2cbaae38014 前提: 只针对Kafka 0.9.0.1版本; 说是运维,其实偏重于问题解决; 大部分解决方案都是google而来 ...

  3. luogu题解P4198楼房重建--线段树神操作

    题目链接 https://www.luogu.org/problemnew/show/P4198 分析 一句话题意,一条数轴上有若干楼房,坐标为\(xi\)的楼房有高度\(hi\),那么它的斜率为\( ...

  4. gcc/g++ 以及makefile

    生成可执行文件   g++ mutiprocess.cpp -o test -fpic:产生位置无关码,位置无关码就是可以在进程的任意内存位置执行的目标码,动态链接库必须使用 -c : 只生成 .o ...

  5. [Scala] java使用scala的jar包问题:Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Short

    场景 刚写的scala处理bmp文件的实验, 打了jar包让java调用一下, 结果发生这个错误. package org.tanglizi.bmp.demo; import org.tanglizi ...

  6. Sql Server 导出数据库表结构的SQL查询语句

    --导出数据库所有表 SELECT 表名 Then D.name Else '' End, 表说明 Then isnull(F.value,'') Else '' End, 字段序号 = A.colo ...

  7. OGG学习笔记03

    OGG学习笔记03-单向复制简单故障处理 环境:参考:OGG学习笔记02-单向复制配置实例实验目的:了解OGG简单故障的基本处理思路. 1. 故障现象故障现象:启动OGG源端的extract进程,da ...

  8. & 位运算总结

    一.& 与  a & -a : 可以计算出 a 的二进制形式的第一个 1 出现的位置. eg: 6 & -6 = 0110 & 1010 = 0010

  9. SmartBinding与kbmMW#2

    前言 在之前的文章中,我介绍了SmartBinding作为Delphi的一个新的易于使用和智能的绑定框架.介绍了包括绑定对象,列表,常规数据和可视控件,以及如何使用导航器,所有这些都用代码做了演示. ...

  10. Tomcat----服务运行的容器

    在介绍Tomcat之前,我们先介绍一个概念Servlet. Servlet是一个运行在WEB服务器上的小的Java程序,用来接收和响应从客户端发送过来的请求,通常使用HTTP协议.从下图可以看出Ser ...