POJ 1741 Tree

Description

Give a tree with n vertices,each edge has a length(positive integer less than 1001). 
Define dist(u,v)=The min distance between node u and v. 
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. 
Write a program that will count how many pairs which are valid for a given tree. 

Input

The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l. 
The last test case is followed by two zeros. 

Output

For each test case output the answer on a single line.

Sample Input

  1. 5 4
  2. 1 2 3
  3. 1 3 1
  4. 1 4 2
  5. 3 5 1
  6. 0 0

Sample Output

  1. 8
    题目大意:有一颗由n个点组成的树,问树上两点间距离小于等于k的点对有多少对
    输入:多组数据输入。每组数据第1nk,接下来n-1行,uvl表示点u与点v之间有一条长为l的边
    输出:点对个数
    基本算法:点分治
    点分治,本质还是分治算法
    对于一棵树,简单的递归搜索的复杂度,呵呵~~,
    所以为了降低复杂度,通俗点儿说就是将一棵树拆开
    一棵树的复杂度之所以高,是因为它有可能很深,
    所以拆要使拆开后的几棵树最深的最小
    那么选取的这个点就是树的重心
    树的重心通俗点儿说就是删除重心后最大的连通块最小
    找出重心后,树上的点的路径就可以分为
    经过重心的 不过重心的
    对于经过重心的,
    1、统计出过重心的所有点的满足条件的数目=ans1
    2、对于每棵子树,统计一遍自己内部满足条件的数目=ans2
    ans=ans1-所有的ans2
    对于不经过重心的,继续递归
    本人点分治理解不深,对点分治更详细的解读 推荐博客:http://www.cnblogs.com/chty/p/5912360.html对于文章中出现的错误,欢迎各位指正
  1. 代码中数组含义:head[],链表 son[i]=j,以i为根的所有子树总共有j个节点(包括i
         f[i]=ji为根的所有子树中,最大的一颗子树有j个节点(不包括i
    sum,当前计算的树或子树的点的个数
         d[i]=j,点i到当前所选的根节点距离为j deep[],d数组的汇总
    代码中函数作用:getroot,找重心 getdeep,统计点之间的距离 cal,统计满足条件的点对数目
    部分代码细节:
    getroot函数:son[x]=1,因为son包含自己 f[x]=0,因为f可能存有上一次的结果
    f[x]=max(f[x],sum-son[x]);①解释了为什么son包含自己,sum是总点数,son[x]是除临时指定的父节点所在子树的子树节点总数,相减就是临时父节点所在子树节点总数
    因为父节点是临时指定的,所以也有可能成为x的孩子节点,所以父节点所在子树也作为x的一颗子树 ②在>2个点时,保证不让叶子节点成为重心
    work函数:root=0 && main函数 f[0]=inf 这两个互相照应,删除选定的根之后,让根=0,因为f[0]=inf,这样在getroot函数里才保证了f[x]<f[root],更新root
  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #define N 10010
  5. #define inf 20001
  6. using namespace std;
  7. int n,k,cnt,head[N],son[N],f[N],sum,ans,root,d[N],deep[N];
  8. bool vis[N];
  9. struct node
  10. {
  11. int next,to,w;
  12. }e[*N];
  13. inline void add(int u,int v,int w)
  14. {
  15. e[++cnt].to=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;
  16. e[++cnt].to=u;e[cnt].w=w;e[cnt].next=head[v];head[v]=cnt;
  17. }
  18. inline void pre()
  19. {
  20. memset(head,,sizeof(head));
  21. memset(vis,false,sizeof(vis));
  22. ans=;cnt=;root=;
  23. }
  24. inline void getroot(int x,int fa)
  25. {
  26. son[x]=;f[x]=;
  27. for(int i=head[x];i;i=e[i].next)
  28. {
  29. if(e[i].to==fa||vis[e[i].to]) continue;
  30. getroot(e[i].to,x);
  31. son[x]+=son[e[i].to];
  32. f[x]=max(f[x],son[e[i].to]);
  33. }
  34. f[x]=max(f[x],sum-son[x]);
  35. if(f[x]<f[root]) root=x;
  36. }
  37. inline void getdeep(int x,int fa)
  38. {
  39. deep[++deep[]]=d[x];
  40. for(int i=head[x];i;i=e[i].next)
  41. {
  42. if(e[i].to==fa||vis[e[i].to]) continue;
  43. d[e[i].to]=d[x]+e[i].w;
  44. getdeep(e[i].to,x);
  45. }
  46. }
  47. inline int cal(int x,int p)
  48. {
  49. d[x]=p;deep[]=;
  50. getdeep(x,);
  51. sort(deep+,deep+deep[]+);
  52. int t=,l,r;
  53. for(l=,r=deep[];l<r;)
  54. {
  55. if(deep[l]+deep[r]<=k) {t+=r-l;l++;}
  56. else r--;
  57. }
  58. return t;
  59. }
  60. inline void work(int x)
  61. {
  62. ans+=cal(x,);
  63. vis[x]=true;
  64. for(int i=head[x];i;i=e[i].next)
  65. {
  66. if(vis[e[i].to]) continue;
  67. ans-=cal(e[i].to,e[i].w);
  68. sum=son[e[i].to];
  69. root=;
  70. getroot(e[i].to,);
  71. work(root);
  72. }
  73. }
  74. int main()
  75. {
  76. while()
  77. {
  78. scanf("%d%d",&n,&k);
  79. if(!n) return ;
  80. pre();
  81. int u,v,w;
  82. for(int i=;i<n;i++)
  83. {
  84. scanf("%d%d%d",&u,&v,&w);
  85. add(u,v,w);
  86. }
  87. sum=n;f[]=inf;
  88. getroot(,);
  89. work(root);
  90. printf("%d\n",ans);
  91. }
  92. }
  1. 加的是无向边,链表忘了开双倍,RE。。。。。。
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define inf 0x7fffffff
  5. using namespace std;
  6. int n,K,cnt,sum,ans,root;
  7. int head[],deep[],d[],f[],son[];
  8. bool vis[];
  9. struct data{int to,next,v;}e[];
  10. inline int read()
  11. {
  12. int x=;char c=getchar();
  13. while(c<''||c>'') c=getchar();
  14. while(c>=''&&c<='') {x=x*+c-'';c=getchar();}
  15. return x;
  16. }
  17. inline void insert(int u,int v,int w)
  18. {
  19. e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].v=w;
  20. e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].v=w;
  21. }
  22. //最小递归层数 why联通的节点数量最小? 不是层数?
  23. inline void getroot(int x,int fa)
  24. {
  25. son[x]=;f[x]=;//son:以x为根的子树的节点个数,包括自己
  26. //f[x]=0 不能删 因为f[x]可能存有上一次的结果
  27. for(int i=head[x];i;i=e[i].next)
  28. {
  29. if(e[i].to==fa||vis[e[i].to]) continue; //vis=true表示节点已删除
  30. getroot(e[i].to,x);
  31. son[x]+=son[e[i].to];
  32. f[x]=max(f[x],son[e[i].to]);
  33. }
  34. f[x]=max(f[x],sum-son[x]);
  35. //树本有根,点分治重新找根,所以以x为根的子树除了已递归到的,还有以父节点为根的子树,这也是son[x]=1的原因
  36. if(f[x]<f[root]) root=x;//找到的根满足它的最大子树最小
  37. }
  38. inline void getdeep(int x,int fa)
  39. {
  40. deep[++deep[]]=d[x];//deep[0]总的节点数,deep 每个点到根节点的距离
  41. for(int i=head[x];i;i=e[i].next)
  42. {
  43. if(e[i].to==fa||vis[e[i].to]) continue;
  44. d[e[i].to]=d[x]+e[i].v;
  45. getdeep(e[i].to,x);
  46. }
  47. }
  48. inline int cal(int x,int now)//now初始为0
  49. {
  50. d[x]=now;deep[]=;//d是长度
  51. getdeep(x,);//得到以x为根的子树中,每个点到x的距离
  52. sort(deep+,deep+deep[]+);
  53. int t=,l,r;
  54. for(l=,r=deep[];l<r;)
  55. {
  56. if(deep[l]+deep[r]<=K) {t+=r-l;l++;}
  57. else r--;
  58. }
  59. return t;
  60. }
  61. inline void work(int x)//x是确定的根
  62. {
  63. ans+=cal(x,);
  64. vis[x]=;
  65. for(int i=head[x];i;i=e[i].next)
  66. {
  67. if(vis[e[i].to]) continue;
  68. ans-=cal(e[i].to,e[i].v);
  69. sum=son[e[i].to];
  70. root=;//删除原根节点后,重新找根节点,f【0】=inf
  71. getroot(e[i].to,root);
  72. work(root);
  73. }
  74. }
  75. int main()
  76. {
  77. while()
  78. {
  79. ans=,root=,cnt=;
  80. memset(vis,,sizeof(vis));
  81. memset(head,,sizeof(head));
  82. n=read();K=read();
  83. if(!n) return ;
  84. for(int i=;i<n;i++)
  85. {
  86. int u=read(),v=read(),w=read();
  87. insert(u,v,w);
  88. }
  89. sum=n;f[]=inf;//sum:用sum-节点已统计的子树节点个数=以节点临时父节点为根的子树节点个数
  90. //f 记录以x为根的最大的子树的大小,最后从f中取最小值
  91. //f[0]=inf 不能删 因为每次getroot 更新root根据f[x]是否小于f[root],每次删除一个点root=0
  92. getroot(,);//找第一个根 ,临时从第1个点开始找
  93. work(root);
  94. printf("%d\n",ans);
  95. }
  96. }

学习时打的注释

  1.  

POJ 1741 Tree 求树上路径小于k的点对个数)的更多相关文章

  1. POJ 1741 Tree(点分治点对<=k)

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

  2. POJ 1741 [点分治][树上路径问题]

    /* 不要低头,不要放弃,不要气馁,不要慌张 题意: 给一棵有n个节点的树,每条边都有一个正权值,求一共有多少个点对使得它们之间路的权值和小于给定的k. 思路: <分治算法在树的路径问题中的应用 ...

  3. [TS-A1505] [清橙2013中国国家集训队第二次作业] 树 [可持久化线段树,求树上路径第k大]

    按Dfs序逐个插入点,建立可持久化线段树,每次查询即可,具体详见代码. 不知道为什么,代码慢的要死,, #include <iostream> #include <algorithm ...

  4. POJ - 1741 Tree

    DescriptionGive a tree with n vertices,each edge has a length(positive integer less than 1001).Defin ...

  5. POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量

    POJ 1741. Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 34141   Accepted: 11420 ...

  6. POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)

    Description A substring of a string T is defined as: T( i, k)= TiTi+1... Ti+k-1, 1≤ i≤ i+k-1≤| T|. G ...

  7. POJ1741--Tree (树的点分治) 求树上距离小于等于k的点对数

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 12276   Accepted: 3886 Description ...

  8. poj 1741 Tree(树的点分治)

    poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出 ...

  9. POJ 1741.Tree 树分治 树形dp 树上点对

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 24258   Accepted: 8062 Description ...

随机推荐

  1. 团队作业之404 Note Found Team

    如果记忆是一个罐头的话,我希望这一罐罐头不会过期----<重庆森林> 404 Note Found Team 如果记忆是一个备忘录的话,别说了,它不会过期----<404 Note ...

  2. python下的Box2d物理引擎的配置

    /******************************* I come back! 由于已经大四了,正在找工作 导致了至今以来第二长的时间内没有更新博客.向大家表示道歉 *********** ...

  3. PHP时间格式化参数表笔记

    date_create_from_format() 函数返回一个根据指定格式进行格式化的新的 DateTime 对象.通常需要配合date_format()函数使用 语法: date_create_f ...

  4. PHP-时间函数

    1.时间格式化函数date(format,timestamp) format 时间格式 timestamp 时间戳 下面列出了一些常用于日期的字符: d - 表示月里的某天(01-31) m - 表示 ...

  5. kafka重新启动时出现:found a corrupted index file due to requirement failed问题解决方法

    问题如下: 解决方法: 删除kafka目录下的日志文件即可解决

  6. PGM学习之四 Factor,Reasoning

    通过上一篇文章的介绍,我们已经基本了解了:Factor是组成PGM模型的基本要素:Factor之间的运算和推理是构建高维复杂PGM模型的基础.那么接下来,我们将重点理解,Factor之间的推理(Rea ...

  7. 014 Java的反射机制

    作者:nnngu GitHub:https://github.com/nnngu 博客园:http://www.cnblogs.com/nnngu 简书:https://www.jianshu.com ...

  8. VRRP主备备份配置示例—实现网关冗余备份

    本示例的基本拓扑结构如图所示. HostA通过Switch 双线连接到RouterA 和RouterB .用户希望实现:正常情况下, 主机以RouterA 为默认网关接入Intemet; 而当Rout ...

  9. java的object类函数详解

    1.clone方法(浅拷贝) 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常. 主要是JAVA里除了8种 ...

  10. MT【145】不变的平面角

    (2018,4月学考数学选择最后一题)如图,设矩形$ABCD$所在平面与梯形$ACEF$所在平面相交于$AC$. 若$AB=1,BC=\sqrt{3},AF=EF=EC=1,$则下面二面角的平面角为定 ...