传送门:http://poj.org/problem?id=1741

写的第一道树分治题,撒花纪念~

对于每一对点对(i, j),它有三种情况:

① 其中一个是根节点。这种情况比较简单,直接加上就好了。

② 横跨根节点。这种情况是重点。

③ 不是以上两种情况。这时递归下去求解就好了。

那么对于第二种情况该怎么破呢?设根节点为root,那么dist(i, root) + dist(j, root) <= k,且需要i与j在不同的子树里。直接算不同子树的点对(i, j)的个数会麻烦,所以需要一点技巧:符合条件且在不同子树的(i, j)的对数 = 符合条件的对数 - 符合条件且在相同子树的(i, j)的对数,这样就搞定啦!

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4.  
  5. const int maxn = 10005;
  6.  
  7. int n, k, t1, t2, t3, ans;
  8. int head[maxn], to[maxn << 1], next[maxn << 1], w[maxn << 1], lb;
  9. int siz[maxn], a[maxn], left, right;
  10. bool book[maxn];
  11.  
  12. inline void ist(int aa, int ss, int ww) {
  13. to[lb] = ss;
  14. next[lb] = head[aa];
  15. head[aa] = lb;
  16. w[lb] = ww;
  17. ++lb;
  18. }
  19. int fnd_zx(int fr, int tot_node, int p, int & rt, int & mn) {
  20. int mx = 0;
  21. for (int j = head[fr]; j != -1; j = next[j]) {
  22. if (!book[to[j]] && to[j] != p) {
  23. fnd_zx(to[j], tot_node, fr, rt, mn);
  24. mx = std::max(mx, siz[to[j]]);
  25. }
  26. }
  27. mx = std::max(mx, tot_node - siz[fr]);
  28. if (mn > mx) {
  29. mn = mx;
  30. rt = fr;
  31. }
  32. }
  33. void get_siz(int fr, int p) {
  34. siz[fr] = 1;
  35. for (int j = head[fr]; j != -1; j = next[j]) {
  36. if (!book[to[j]] && to[j] != p) {
  37. get_siz(to[j], fr);
  38. siz[fr] += siz[to[j]];
  39. }
  40. }
  41. }
  42. void get_data(int r, int p, int ww) {
  43. if (ww > k) {
  44. return;
  45. }
  46. a[right++] = ww;
  47. for (int j = head[r]; j != -1; j = next[j]) {
  48. if (!book[to[j]] && to[j] != p) {
  49. get_data(to[j], r, ww + w[j]);
  50. }
  51. }
  52. }
  53. int get_ans(int l, int r) {
  54. std::sort(a + l, a + r);
  55. int rt = 0;
  56. --r;
  57. while (r > l) {
  58. while (r > l && a[l] + a[r] > k) {
  59. --r;
  60. }
  61. rt += r - l;
  62. ++l;
  63. }
  64. return rt;
  65. }
  66. void slove(int fr) {
  67. int root = -666, mn = 2147483647;
  68. get_siz(fr, 0);
  69. fnd_zx(fr, siz[fr], 0, root, mn);
  70. book[root] = true;
  71. for (int j = head[root]; j != -1; j = next[j]) {
  72. if (!book[to[j]]) {
  73. slove(to[j]);
  74. }
  75. }
  76. left = right = 0;
  77. for (int j = head[root]; j != -1; j = next[j]) {
  78. if (!book[to[j]]) {
  79. get_data(to[j], root, w[j]);
  80. ans -= get_ans(left, right);
  81. left = right;
  82. }
  83. }
  84. ans += get_ans(0, right) + right;
  85. book[root] = false;
  86. }
  87.  
  88. int main(void) {
  89. //freopen("in.txt", "r", stdin);
  90. while (scanf("%d%d", &n, &k) && n && k) {
  91. lb = 0;
  92. memset(head, -1, sizeof head);
  93. memset(next, -1, sizeof next);
  94. ans = 0;
  95. for (int i = 1; i < n; ++i) {
  96. scanf("%d%d%d", &t1, &t2, &t3);
  97. ist(t1, t2, t3);
  98. ist(t2, t1, t3);
  99. }
  100. slove(1);
  101. printf("%d\n", ans);
  102. }
  103. return 0;
  104. }

  

[POJ1741] Tree【树分治 点分治】的更多相关文章

  1. POJ1741——Tree(树的点分治)

    1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...

  2. 【poj1741】Tree 树的点分治

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

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

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

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

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

  5. POJ1741 Tree 树分治模板

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. win7右下角无线网图标显示未连接,但是实际上已连接上,也能上网

    首先,要确实是不是服务启动的问题,方法很简单,重新启动电脑就可以. 如果问题依旧,那么按下Win+R快捷键,输入“services.msc”,打开服务界面. 然后会看到右侧窗口出现好多设置项,找到“R ...

  2. js 判断对象中所有属性是否为空

    测试: var obj = {a:"123",b:""}; for(var key in obj){ if(!obj[key]) return; } 函数封装: ...

  3. 【Mongodb教程 第五课 】MongoDB 删除集合

    drop() 方法 MongoDB 的 db.collection.drop() 是用来从数据库中删除一个集合. 语法: drop() 命令的基本语法如下 db.COLLECTION_NAME.dro ...

  4. 最简单实用的MongoDB安装教程:在CentOS中使用 yum 安装MongoDB及服务器端配置详解

    一.准备工作: 运行yum命令查看MongoDB的包信息 [root@vm ~]# yum info mongo-10gen (提示没有相关匹配的信息,) 说明你的centos系统中的yum源不包含M ...

  5. wpf 导出Excel Wpf Button 样式 wpf简单进度条 List泛型集合对象排序 C#集合

    wpf 导出Excel   1 private void Button_Click_1(object sender, RoutedEventArgs e) 2 { 3 4 ExportDataGrid ...

  6. 【Java报错】Message: 3 字节的 UTF-8 序列的字节 2 无效

    报错logs 2015-03-10 10:15:32,360 ERROR [qtp32195030-27] [InvokeAfterValve.java:55] - javax.xml.stream. ...

  7. CentOS7.2 设置GRUB2引导界面分辨率

    最近在学习OS引导启动,GRUB2的学习材料也不少,主要还看官方手册清晰些. 公司里办公机的多启动用的ubuntu的界面,还挺炫酷的.之前看其他博客网文里看到可以设置grub2的分辨率,我拿CentO ...

  8. Java String 和 new String()的区别

    Java String 和 new String()的区别 本文转自:http://www.cnblogs.com/heima-jieqi/archive/2012/04/10/2440086.htm ...

  9. [学习笔记]dsu on a tree(如何远离线段树合并)

    https://www.zybuluo.com/ysner/note/1318613 背景 这玩意来源于一种有局限性的算法. 有一种广为人知的,树上离线维护子树信息的做法. (可以参照luogu360 ...

  10. bzoj 2006 超级钢琴 —— ST表

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2006 本来应该是可以用主席树,找区间最小值,取出来后再找那段区间的次小值...... 但也可 ...