当前位置:   article > 正文

『You Are Given a Tree 整体分治 树形dp』

you are given a tree with n vertices. for each = 1 , 2 , … ,


You Are Given a Tree

Description

A tree is an undirected graph with exactly one simple path between each pair of vertices. We call a set of simple paths k -valid if each vertex of the tree belongs to no more than one of these paths (including endpoints) and each path consists of exactly k vertices.

You are given a tree with nn vertices. For each k from 1 to nn inclusive find what is the maximum possible size of a k -valid set of simple paths.

Input Format

The first line of the input contains a single integer n ( 2≤n≤100000 ) — the number of vertices in the tree.

Then following n - 1 lines describe the tree, each of them contains two integers v , u ( 1≤v,u≤n ) — endpoints of the corresponding edge.

It is guaranteed, that the given graph is a tree.

Output Format

Output n numbers, the i -th of which is the maximum possible number of paths in an i -valid set of paths.

Sample Input

  1. 7
  2. 1 2
  3. 2 3
  4. 3 4
  5. 4 5
  6. 5 6
  7. 6 7

Sample Output

  1. 7
  2. 3
  3. 2
  4. 1
  5. 1
  6. 1
  7. 1

解析

可以先考虑k确定时的做法,不妨进行树形dpf[x]代表以x为根的子树中最长链的长度,同时维护一下全局答案。转移方式就是能合并就合并,反之选一条最长的链向上延伸,时间复杂度O(n)

我们发现kn时答案最多只有n种取值,k>n时答案n,也只有n种取值,并且答案的大小具有单调性,于是就有一个很直观的想法,二分找到段边界,统一每一段的答案即可,时间复杂度O(nnlog2n)

但是直接这样写常数可能比较大,换一种整体二分的写法常数更小一些,时间复杂度不变,就可以通过本题了。

Code:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 100020;
  4. struct edge { int ver,next; } e[N*2];
  5. int n,t,Head[N],f[N],cnt,ans[N];
  6. inline void insert(int x,int y) { e[++t] = (edge){y,Head[x]} , Head[x] = t; }
  7. inline void input(void)
  8. {
  9. scanf("%d",&n);
  10. for (int i=1;i<n;i++)
  11. {
  12. int x,y;
  13. scanf("%d%d",&x,&y);
  14. insert( x , y );
  15. insert( y , x );
  16. }
  17. }
  18. inline void dp(int x,int fa,int len)
  19. {
  20. int Max = 0 , sec = 0;
  21. for (int i=Head[x];i;i=e[i].next)
  22. {
  23. int y = e[i].ver;
  24. if ( y == fa ) continue;
  25. dp( y , x , len );
  26. if ( f[y] >= Max ) sec = Max , Max = f[y];
  27. else if ( f[y] > sec ) sec = f[y];
  28. }
  29. if ( sec + Max + 1 >= len ) f[x] = 0 , cnt++;
  30. else f[x] = Max + 1;
  31. }
  32. inline void divide(int st,int ed,int l,int r)
  33. {
  34. if ( st > ed || l > r ) return;
  35. if ( l == r )
  36. {
  37. for (int i=st;i<=ed;i++) ans[i] = l;
  38. return;
  39. }
  40. int mid = st + ed >> 1; cnt = 0;
  41. dp( 1 , 0 , mid );
  42. ans[mid] = cnt;
  43. divide( st , mid-1 , cnt , r );
  44. divide( mid+1 , ed , l , cnt );
  45. }
  46. int main(void)
  47. {
  48. input();
  49. divide( 1 , n , 0 , n );
  50. for (int i=1;i<=n;i++)
  51. printf("%d\n",ans[i]);
  52. return 0;
  53. }

转载于:https://www.cnblogs.com/Parsnip/p/11415261.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/75119
推荐阅读
相关标签
  

闽ICP备14008679号