先用dijkstra把最短路树建出来,然后就是树的质心分治了。

经过k个点的路径,要么全在子树上,要么经过根结点,因此可以分治。

如果分治的时候选点不好会变成O(n^2),比较极端的情况是比如树是一条链。

选择质心可以保证最大子树结点不超过n/2,每次递归至少减半,递归层数是O(logn)的。

找子树质心是O(n)的树形dp,枚举到根结点的路径是O(n)的。

把经过根节点并且路径上有c个结点的最长路径以及方案保存到一个map,对于一条新增的路径去查找k-c个点的路径,就可以更新答案了。

如果用的unorder_map,那么查找是O(1)的,因此分治复杂度是T(n) = 2*T(n/2) + O(n) ≈ O(nlogn)。

总体复杂度是O(mlogn + nlogn)

  1. /*********************************************************
  2. * ------------------ *
  3. * author AbyssFish *
  4. **********************************************************/
  5. #include<cstdio>
  6. #include<iostream>
  7. #include<string>
  8. #include<cstring>
  9. #include<queue>
  10. #include<vector>
  11. #include<stack>
  12. #include<map>
  13. #include<set>
  14. #include<algorithm>
  15. #include<cmath>
  16. #include<numeric>
  17. #include<climits>
  18. #include<unordered_map>
  19. using namespace std;
  20.  
  21. const int maxn = +;
  22. const int maxm = *+;
  23.  
  24. typedef long long ll;
  25. #define sInt 4
  26. int hd[maxn], nx[maxm], to[maxm], we[maxm], ec;
  27. #define eachedge int i = hd[u]; ~i; i = nx[i]
  28. void init_g(int n){ memset(hd+,0xff,sInt*n); ec = ; }
  29. void add_edge(int u,int v,int c)
  30. {
  31. to[ec] = v;
  32. we[ec] = c;
  33. nx[ec] = hd[u];
  34. hd[u] = ec++;
  35. }
  36.  
  37. int n,m,k;
  38.  
  39. int di[maxn], fe[maxn];
  40. typedef pair<int,int> pii;
  41. #define dist first
  42. #define ver second
  43. priority_queue<pii,vector<pii>,greater<pii> > q;
  44.  
  45. void dijkstra()
  46. {
  47. memset(di+,0x3f,sInt*n);
  48.  
  49. di[] = ; fe[] = -;
  50. q.push(pii(,));
  51. while(!q.empty()){
  52. pii x = q.top(); q.pop();
  53. if(x.dist != di[x.ver]) continue;
  54. int u = x.ver;
  55. for(int i = hd[u]; ~i; i = nx[i]){
  56. int v = to[i];
  57. if(di[v] > di[u] + we[i]){
  58. di[v] = di[u]+we[i];
  59. fe[v] = i;
  60. q.push(pii(di[v],v));
  61. }
  62. else if(di[v] == di[u] + we[i] && to[fe[v]^] > u){
  63. fe[v] = i;
  64. }
  65. }
  66. }
  67. }
  68.  
  69. void rewrite(int u,int i)
  70. {
  71. nx[i] = hd[u];
  72. hd[u] = i;
  73. }
  74.  
  75. void build_tree()
  76. {
  77. dijkstra();
  78. init_g(n);
  79. for(int v = ; v <= n; v++){
  80. int e = fe[v];
  81. int u = to[e^];
  82. rewrite(u,e);
  83. rewrite(v,e^);
  84. }
  85. }
  86.  
  87. bool vis_c[maxn];
  88. int tr_sz[maxn];
  89.  
  90. void cal_tr_sz(int u,int f)
  91. {
  92. int &c = tr_sz[u];
  93. c = ;
  94. for(eachedge){
  95. int v = to[i];
  96. if(v == f || vis_c[v]) continue;
  97. c += tr_sz[v];
  98. cal_tr_sz(v,u);
  99. }
  100. }
  101.  
  102. int block_size;
  103. int best, centroid;
  104. void findCentroid(int u,int f)
  105. {
  106. int mx = ;
  107. for(eachedge){
  108. int v = to[i];
  109. if(v == f || vis_c[v]) continue;
  110. findCentroid(v,u);
  111. mx = max(mx, tr_sz[v]);
  112. }
  113. mx = max(mx,block_size-tr_sz[u]);
  114. if(best > mx){
  115. best = mx;
  116. centroid = u;
  117. }
  118. }
  119.  
  120. typedef unordered_map<int,pii> cont;
  121. typedef cont::iterator con_it;
  122. //key 经过的点数,value(最长距离,方案数)
  123. cont prv;
  124. cont tmp;
  125.  
  126. void update(cont &res,int c, const pii &np)
  127. {
  128. con_it it = res.find(c);
  129. if(it != res.end()){
  130. pii &p = it->second;
  131. if(p.dist == np.dist) p.ver += np.ver;
  132. else if(p.dist < np.dist) {
  133. p = np;
  134. }
  135. }
  136. else {
  137. res.insert(make_pair(c,np));
  138. }
  139. }
  140.  
  141. void enum_path(int u,int f,int c,int d,cont &res)
  142. {
  143. if(c >= k) return;
  144. update(res,c,pii(d,));
  145.  
  146. for(eachedge){
  147. int v = to[i];
  148. if(v == f || vis_c[v]) continue;
  149. enum_path(v,u,c+,d+we[i],res);
  150. }
  151. }
  152.  
  153. int ans;
  154. ll cnt;
  155.  
  156. void divide(int rt)
  157. {
  158. cal_tr_sz(rt,-);
  159. best = INT_MAX;
  160. block_size = tr_sz[rt];
  161. findCentroid(rt,-);
  162. int u = centroid;
  163. vis_c[u] = true;
  164.  
  165. for(eachedge){
  166. if(!vis_c[to[i]]) divide(to[i]);
  167. }
  168.  
  169. prv.clear();
  170. prv.insert(make_pair(,pii(,)));
  171. for(eachedge){
  172. if(vis_c[to[i]]) continue;
  173. tmp.clear();
  174. enum_path(to[i],u,,we[i],tmp);
  175. con_it it, it2;
  176. for(it = tmp.begin(); it != tmp.end(); it++){
  177. int c = it->first;
  178. pii &p = it->second;
  179. if((it2 = prv.find(k-c)) != prv.end()){
  180. ll dis = it2->second.dist + p.dist;
  181. if(dis > ans){
  182. ans = dis; cnt = p.ver * it2->second.ver;
  183. }
  184. else if(dis == ans) cnt += p.ver * it2->second.ver;
  185. }
  186. }
  187.  
  188. for(it = tmp.begin(); it != tmp.end(); it++){
  189. int c = it->first+;
  190. update(prv,c,it->second);
  191. }
  192. }
  193.  
  194. vis_c[u] = false;
  195. }
  196.  
  197. void solve()
  198. {
  199. build_tree();
  200. ans = cnt = ;
  201. divide();
  202. printf("%d %lld\n",ans,cnt);
  203. }
  204.  
  205. void init()
  206. {
  207. scanf("%d%d%d",&n,&m,&k);
  208. init_g(n);
  209. for(int i = ; i < m; i++){
  210. int a,b,c; scanf("%d%d%d",&a,&b,&c);
  211. add_edge(a,b,c);
  212. add_edge(b,a,c);
  213. }
  214. }
  215.  
  216. //#define LOCAL
  217. int main()
  218. {
  219. #ifdef LOCAL
  220. freopen("in.txt","r",stdin);
  221. #endif
  222. int T; scanf("%d",&T);
  223. while(T--){
  224. init();
  225. solve();
  226. }
  227. return ;
  228. }

HDU 4871 Shortest-path tree的更多相关文章

  1. hdu 3631 Shortest Path(Floyd)

    题目链接:pid=3631" style="font-size:18px">http://acm.hdu.edu.cn/showproblem.php?pid=36 ...

  2. HDU 5636 Shortest Path 暴力

    Shortest Path 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 Description There is a path graph ...

  3. HDU 5636 Shortest Path(Floyed,枚举)

    Shortest Path Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Tot ...

  4. HDU - 3631 Shortest Path(Floyd最短路)

    Shortest Path Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u SubmitStat ...

  5. HDU - 4725_The Shortest Path in Nya Graph

    The Shortest Path in Nya Graph Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...

  6. hdu 3631 Shortest Path

    floyd算法好像很奇妙的样子.可以做到每次加入一个点再以这个点为中间点去更新最短路,效率是n*n. #include<cstdio> #include<cstring> #i ...

  7. HDU 5636 Shortest Path

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 题解: 1.暴力枚举: #include<cmath> #include<c ...

  8. HDU 5636 Shortest Path 分治+搜索剪枝

    题意:bc round 74 分析(官方题解): 你可以选择分类讨论, 但是估计可能会写漏一些地方. 只要抽出新增边的端点作为关键点, 建立一个新图, 然后跑一遍floyd就好了. 复杂度大概O(6^ ...

  9. HDU 5636 Shortest Path(Floyd)

    题目链接  HDU5636 n个点,其中编号相邻的两个点之间都有一条长度为1的边,然后除此之外还有3条长度为1的边. m个询问,每次询问求两个点之前的最短路. 我们把这三条边的6个点两两算最短路, 然 ...

  10. HDU 4479 Shortest path 带限制最短路

    题意:给定一个图,求从1到N的递增边权的最短路. 解法:类似于bellman-ford思想,将所有的边先按照权值排一个序,然后依次将边加入进去更新,每条边只更新一次,为了保证得到的路径是边权递增的,每 ...

随机推荐

  1. 2.Servlet(一)

    1.Servlet的编写.访问过程: (1)编写部署Servlet程序: 编写源文件->编译类文件->部署程序->运行->Servlet处理请求,返回响应. (2)Eclips ...

  2. HIVE sql取中文

    select regexp_replace(str,'[^\\u4e00-\\u9fa5]','') as str1 from ( select 'test测试test' as str ) t ;

  3. 线程池ThreadPoolExecutor分析: 线程池是什么时候创建线程的,队列中的任务是什么时候取出来的?

    带着几个问题进入源码分析: 1. 线程池是什么时候创建线程的? 2. 任务runnable task是先放到core到maxThread之间的线程,还是先放到队列? 3. 队列中的任务是什么时候取出来 ...

  4. my18_mysql中的几个超时时间

    连接的超时时间 set global interactive_timeout=120;set global wait_timeout=120; 该连接指类似应用访问数据库的连接,可以是查询.DML.D ...

  5. vue混入(mixins)

    混入(mixins)是一种分发vue组件中可复用功能的非常灵活的方式.混入对象可以包含任意组件选项. 当组件使用混入对象时,所以混入对象的选项将被混入该组件本身选项,当组件和混入对象含有同名选项时,这 ...

  6. MySQL · 引擎特性 · InnoDB index lock前世今生

    http://mysql.taobao.org/monthly/2015/07/05/ MySQL · 引擎特性 · InnoDB index lock前世今生 前言 InnoDB并发过程中使用两类锁 ...

  7. (转)linux常见故障一:linux 文件系统变只读

    linux常见故障一:linux 文件系统变只读 原文:https://www.cnblogs.com/ginvip/p/6375672.html 1. 重启系统看是否可以自动修复. 2. 使用fsc ...

  8. redis开机启动,有密码

    #!/bin/sh # chkconfig: # description: Start and Stop redis REDISPORT= EXEC=/usr/local/redis/src/redi ...

  9. HDU 2121——Ice_cream’s world II——————【最小树形图、不定根】

    Ice_cream’s world II Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64 ...

  10. AngularJS 学习(-)Hello world

    早期的AngularJS使我们的前端开发模式发生很大的变化,基使用MVC. Model - html 模板:Controller - js脚本; Model 来自于Web API 或其他Service ...