[关闭]
@ysner 2018-09-21T08:13:28.000000Z 字数 2073 阅读 1501

[Poi2004]SZN

贪心 二分


题面

给一棵树,问最少要用多少条不相交的链,才能覆盖整棵树;并在此基础上,最小化其中最长链的长度。

解析

第一问直接贪心即可。
若该点有个儿子,则有条链。我们可以把这条链两两配对,若有多出的链,就延伸到该点父亲去。则形成条链(在链的最高点统计个数)。
而根节点号没有父亲,所以形成条链。

“最大值的最小值”问题显然需要二分。
先二分答案。
为从下往上延伸到点的链的长度。
然后在每个点中,把儿子中最长链与最短链合并,次长链和次短链合并。。。尽量使所有链长符合要求。
在符合要求的基础上,使向上延伸的链的长度尽量短。
这里又可以二分,二分那条向上延伸的链。

但是要注意一点,
存在一种情况:某点有偶数个儿子时,不一定要把条链一一配对完毕;一条链不配对,另一条链向上延伸也是可以的

复杂度
有些小细节。(看打了标记的行)

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #include<vector>
  8. #define ll long long
  9. #define re register
  10. #define il inline
  11. #define pb(a) push_back(a)
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int N=1e5+100;
  16. int n,h[N],cnt,in[N],ans,f[N],tot;
  17. struct Edge{int to,nxt;}e[N<<1];
  18. vector<int>son[N];
  19. il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}
  20. il ll gi()
  21. {
  22. re ll x=0,t=1;
  23. re char ch=getchar();
  24. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  25. if(ch=='-') t=-1,ch=getchar();
  26. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  27. return x*t;
  28. }
  29. il int calc(re int u,re int p,re int w)
  30. {
  31. re int l=-1,r=tot;
  32. while(l<r)
  33. {
  34. ++l;--r;
  35. if(l==p) ++l;if(r==p) --r;
  36. if(son[u][l]+son[u][r]>w) return 0;
  37. }
  38. return 1;
  39. }
  40. il int dfs(re int u,re int fa,re int w)
  41. {
  42. for(re int i=h[u];i+1;i=e[i].nxt)
  43. {
  44. re int v=e[i].to;
  45. if(v==fa) continue;
  46. if(!dfs(v,u,w)) return 0;//
  47. son[u].pb(f[v]+1);
  48. }
  49. if(!son[u].size()) {f[u]=0;return 1;}//
  50. if(u!=1&&son[u].size()%2==0) son[u].pb(0);
  51. sort(son[u].begin(),son[u].end());
  52. tot=son[u].size();
  53. if(u==1&&tot%2==0)
  54. {
  55. f[u]=0;
  56. if(!calc(u,-10,w)) return 0;
  57. }
  58. else
  59. {
  60. re int l=0,r=tot-1,p=-1;
  61. while(l<=r)
  62. {
  63. re int mid=l+r>>1;
  64. if(calc(u,mid,w)) p=mid,r=mid-1;
  65. else l=mid+1;
  66. }
  67. if(p==-1) return 0;
  68. f[u]=son[u][p];
  69. }
  70. return f[u]<=w;//
  71. }
  72. il int check(re int x)
  73. {
  74. fp(i,1,n) son[i].clear(),f[i]=0;
  75. return dfs(1,0,x);
  76. }
  77. int main()
  78. {
  79. freopen("2067.in","r",stdin);
  80. freopen("2067.out","w",stdout);
  81. memset(h,-1,sizeof(h));
  82. n=gi();
  83. fp(i,1,n-1)
  84. {
  85. re int u=gi(),v=gi();
  86. add(u,v);add(v,u);++in[u];++in[v];
  87. }
  88. ans+=(in[1]+1)/2;
  89. fp(i,2,n) ans+=(in[i]-1)/2;
  90. printf("%d ",ans);
  91. re int l=1,r=n,ans=1;
  92. while(l<=r)
  93. {
  94. re int mid=l+r>>1;
  95. if(check(mid)) ans=mid,r=mid-1;
  96. else l=mid+1;
  97. }
  98. printf("%d\n",ans);
  99. return 0;
  100. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注