1. 1 /* ***********************************************
  2. 2 Author :kuangbin
  3. 3 Created Time :2013-11-17 14:30:29
  4. 4 File Name :E:\2013ACM\专题学习\树的分治\POJ1741.cpp
  5. 5 ************************************************ */
  6. 6
  7. 7 #include <stdio.h>
  8. 8 #include <string.h>
  9. 9 #include <iostream>
  10. 10 #include <algorithm>
  11. 11 #include <vector>
  12. 12 #include <queue>
  13. 13 #include <set>
  14. 14 #include <map>
  15. 15 #include <string>
  16. 16 #include <math.h>
  17. 17 #include <stdlib.h>
  18. 18 #include <time.h>
  19. 19 using namespace std;
  20. 20 const int MAXN = 10010;
  21. 21 const int INF = 0x3f3f3f3f;
  22. 22 struct Edge
  23. 23 {
  24. 24 int to,next,w;
  25. 25 }edge[MAXN*2];
  26. 26 int head[MAXN],tot;
  27. 27 void init()
  28. 28 {
  29. 29 tot = 0;
  30. 30 memset(head,-1,sizeof(head));
  31. 31 }
  32. 32 void addedge(int u,int v,int w)
  33. 33 {
  34. 34 edge[tot].to = v; edge[tot].w = w;
  35. 35 edge[tot].next = head[u];head[u] = tot++;
  36. 36 }
  37. 37 bool vis[MAXN];
  38. 38 int size[MAXN],dep[MAXN];
  39. 39 int le,ri;
  40. 40 int dfssize(int u,int pre)
  41. 41 {
  42. 42 size[u] = 1;
  43. 43 for(int i = head[u];i != -1;i = edge[i].next)
  44. 44 {
  45. 45 int v = edge[i].to;
  46. 46 if(v == pre || vis[v])continue;
  47. 47 size[u] += dfssize(v,u);
  48. 48 }
  49. 49 return size[u];
  50. 50 }
  51. 51 int minn;
  52. 52 //找重心
  53. 53 void getroot(int u,int pre,int totnum,int &root)
  54. 54 {
  55. 55 int maxx = totnum - size[u];
  56. 56 for(int i = head[u];i != -1;i = edge[i].next)
  57. 57 {
  58. 58 int v = edge[i].to;
  59. 59 if(v == pre || vis[v])continue;
  60. 60 getroot(v,u,totnum,root);
  61. 61 maxx = max(maxx,size[v]);
  62. 62 }
  63. 63 if(maxx < minn){minn = maxx; root = u;}
  64. 64 }
  65. 65 void dfsdepth(int u,int pre,int d)
  66. 66 {
  67. 67 dep[ri++] = d;
  68. 68 for(int i = head[u];i != -1;i = edge[i].next)
  69. 69 {
  70. 70 int v = edge[i].to;
  71. 71 if(v == pre || vis[v])continue;
  72. 72 dfsdepth(v,u,d+edge[i].w);
  73. 73 }
  74. 74 }
  75. 75 int k;
  76. 76 int getdep(int a,int b)
  77. 77 {
  78. 78 sort(dep+a,dep+b);
  79. 79 int ret = 0, e = b-1;
  80. 80 for(int i = a;i < b;i++)
  81. 81 {
  82. 82 if(dep[i] > k)break;
  83. 83 while(e >= a && dep[e] + dep[i] > k)e--;
  84. 84 ret += e - a + 1;
  85. 85 if(e > i)ret--;
  86. 86 }
  87. 87 return ret>>1;
  88. 88 }
  89. 89 int solve(int u)
  90. 90 {
  91. 91 int totnum = dfssize(u,-1);
  92. 92 int ret = 0;
  93. 93 minn = INF;
  94. 94 int root;
  95. 95 getroot(u,-1,totnum,root);
  96. 96 vis[root] = true;
  97. 97 for(int i = head[root];i != -1;i = edge[i].next)
  98. 98 {
  99. 99 int v = edge[i].to;
  100. 100 if(vis[v])continue;
  101. 101 ret += solve(v);
  102. 102 }
  103. 103 le = ri = 0;
  104. 104 for(int i = head[root];i != -1;i = edge[i].next)
  105. 105 {
  106. 106 int v = edge[i].to;
  107. 107 if(vis[v])continue;
  108. 108 dfsdepth(v,root,edge[i].w);
  109. 109 ret -= getdep(le,ri);
  110. 110 le = ri;
  111. 111 }
  112. 112 ret += getdep(0,ri);
  113. 113 for(int i = 0;i < ri;i++)
  114. 114 {
  115. 115 if(dep[i] <= k)ret++;
  116. 116 else break;
  117. 117 }
  118. 118 vis[root] = false;
  119. 119 return ret;
  120. 120 }
  121. 121
  122. 122 int main()
  123. 123 {
  124. 124 //freopen("in.txt","r",stdin);
  125. 125 //freopen("out.txt","w",stdout);
  126. 126 int n;
  127. 127 int u,v,w;
  128. 128 while(scanf("%d%d",&n,&k) == 2)
  129. 129 {
  130. 130 if(n == 0 && k == 0)break;
  131. 131 init();
  132. 132 for(int i = 1;i < n;i++)
  133. 133 {
  134. 134 scanf("%d%d%d",&u,&v,&w);
  135. 135 addedge(u,v,w);
  136. 136 addedge(v,u,w);
  137. 137 }
  138. 138 memset(vis,false,sizeof(vis));
  139. 139 printf("%d\n",solve(1));
  140. 140 }
  141. 141 return 0;
  142. 142 }

树的分治算法——基于点的分治

首先选取一个点将无根树转为有根树,再递归处理每一颗以根结点的儿子为根的子树。

给定一颗N(1<=N<=10000)个结点的带权树,定义dist(u,v)为u,v两点间的最短路径长度,路径的长度定义为路径上所有边的权和。

再给定一个K(1<=K<=10^9),如果对于不同的两个结点a,b,如果满足dist(a,b)<=K,则称(a,b)为合法点对。

求合法点对个数。

算法分析:

如果使用普通的DFS遍历,时间复杂度高达O(N^2),而使用时间复杂度为O(NK)的动态规划,更是无法在规定时限内出解的。

我们知道一条路径要么过根结点,要么在一颗子树中,这启发了我们可以使用分治算法。

路径在子树中的情况只需递归处理即可,下面我们来分析如何处理路径过根结点的情况。

记Depth(i)表示点i到根结点的路径长度,Belong(i)=X(X为根结点的某个儿子,且结点i在以X为根的子树内)。那么我们要统计的就是:

满足Depth(i)+Depth(j)<=K且Belong(i)!=Belong(j)的(i,j)个数

=满足Depth(i)+Depth(j)<=K的(i,j)个数

- 满足Depth(i)+Depth(j)<=K的(i,j)个数且Belong(i)==Belong(j)的(i,j)个数

而对于这两个部分,都是要求出满足Ai+Aj<=K的(i,j)的对数。将A排序后利用单调性可以得出一个O(N)的算法,所以可以用O(NlogN)的时间来解决这个问题。

综上,此题使用树的点分治算法时间复杂度为O(Nlog2N)。

所谓点分治,对于一条树路径,只有经过或不经过一个点的情况。

对于不经过的情况 把一棵树按这个点拆成好几棵分治就行了。

(楼天城男人八题,漆子超IOI2009国家集训队论文)

POJ1741——Tree(树的点分治)的更多相关文章

  1. 【poj1741】Tree 树的点分治

    题目描述 Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dis ...

  2. hdu 4812 D Tree(树的点分治)

    D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total ...

  3. [poj1741][tree] (树/点分治)

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

  4. POJ1741 Tree 树分治模板

    http://poj.org/problem?id=1741   题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数.   dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...

  5. POJ1741(SummerTrainingDay08-G 树的点分治)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 23380   Accepted: 7748 Description ...

  6. hdu4812-D Tree (树的点分治)

    昨天学了下树分治,今天补这道题,还是太不熟练了,写完之后一直超时.后来查出好多错= =比如v,u写倒了,比如+写成了取最值,比如....爆int...查了两个多小时的错..哭...(没想到进首页了 h ...

  7. 【POJ 1741】 Tree (树的点分治)

    Tree   Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...

  8. 树上点对统计poj1741(树的点分治)

    给定一棵树,边上有权值,要统计有多少对点路径的权值和<=k 分治算法在树的路径中的应用 这个论文里面有分析. 任意两点的路径,要么过根结点,要么在子树中.如果在子树中,那么只要递归处理就行了. ...

  9. POJ 1741 Tree(树的点分治,入门题)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description ...

随机推荐

  1. STM32启动文件详解及SystemInit函数分析(转)

    ;先在RAM中分配系统使用的栈,RAM的起始地址为0x2000_0000 ;然后在RAM中分配变量使用的堆 ;然后在CODE区(flash)分配中断向量表,flash的起始地址为0x0800_0000 ...

  2. Java Swing 盒布局管理器

    Swing 盒布局管理器 因为项目的原因,重新看看swing的东西,在想要将两个横向的容器纵向表示的时候,发现用盒布局 话不多说,直接代码 package ui; import javax.swing ...

  3. 【笔记】ROC曲线

    ROC曲线 前文讲了PR曲线 这里说ROC曲线,其描述的是TPR和FPR之间的关系 TPR是什么呢,TPR就是召回率 FPR是什么呢,FPR就是和TPR对应的,即真实值为0的一行中的预测为1的部分比例 ...

  4. 结合scipy.linalg在Python中使用线性系统

    摘要:将线性代数概念应用到实际问题中scipy.linalg 使用 Python 和 NumPy处理向量和矩阵 使用线性系统模拟实际问题 使用求解线性系统 scipy.linalg 本文分享自华为云社 ...

  5. Error running 'Tomcat 9.0.24': port out of range:-1

    修改tomcat安装目录下的conf--server.xml检查一下,端口不能是-1, 一般会选80,或者1-65535之间的任意一个整数

  6. vs code 调试angular2

    调试步骤: 1.安装nodejs 2.安装vscode 3.vscode安装debugger for chrome插件 4.选择调试->打开调试配置,选择chrome配置,打开lauch.jso ...

  7. sudo apt install net-tools [sudo] zyw 的密码: 正在读取软件包列表... 完成 正在分析软件包的依赖关系树,正在读取状态信息... 完成,没有可用的软件包 net-tools,但是它被其它的软件包引用了。这可能意味着这个缺失的软件包可能已被废弃,或者只能在其他发布源中找到

    截图: 先执行: sudo apt-get update 再执行: sudo apt install net-tools 即可安装成功!!

  8. MySQL主从复制与Atlas读写分离

    配置主从复制 1. 增加主从配置 # 主库配置文件 server-id = 1 log-bin = /var/lib/mysql/mysql-bin expire_logs_days = 10 ski ...

  9. C# 异步锁

    参考网址: https://www.cnblogs.com/Alicia-meng/p/13330640.html 使用SemaphoreSlim 实现 当多个任务或线程并行运行时,难以避免的对某些有 ...

  10. C++11 shared_ptr智能指针(超级详细)

    在实际的 C++ 开发中,我们经常会遇到诸如程序运行中突然崩溃.程序运行所用内存越来越多最终不得不重启等问题,这些问题往往都是内存资源管理不当造成的.比如: 有些内存资源已经被释放,但指向它的指针并没 ...