[关闭]
@Rarfaeal 2019-11-29T06:28:44.000000Z 字数 2910 阅读 355

树上所有路径 的个数

根 :
对于每一条边 , 包含两种情况 :

先考虑第一种情况
我们遍历子树 , 求出
如果 的话 , 停止对 子树的枚举

易得 ,
也就是说这条路径存在于不同的两个子树当中 , 或者顶点为
对于顶点为 , 这个很好统计
对于前者 , 那我们对于每一个子树的遍历 , 提取
最后再把自己的贡献弄上去 , 用线段树即可
复杂度

考虑第二种情况
我们必须要把 抹除才能达到 的条件
我们可以发现

所以说后面那个东西其实就是子树的答案
那我我们直接递归到子树中去就可以了
考虑到一个问题 , 如果直接递归下去 , 复杂度为

所以要从重心下去 , 找的复杂度是 , 一共会找 次 , , 而 平均为 , 这个东西骤于 的。

而这个重心怎么找 ?
我们用上一次的 ,如果这家伙的 为先前的一半(或者差不多)的话 , 就可以了

时间复杂度 , 优秀

  1. Const
  2. root=1;
  3. total=1000;
  4. var
  5. cnt,size,tree,next,from,reach,value:array[-1..total] of longint;
  6. i,j,n,k,a,b,c,tot,ans:longint;
  7. procedure Link(x,y,sum:longint);
  8. begin
  9. inc(tot); from[tot]:=x; reach[tot]:=y; value[tot]:=sum;
  10. next[tot]:=cnt[x]; cnt[x]:=tot;
  11. end;
  12. function Query(l,r,k,x,y:longint):longint;
  13. var mid:longint;
  14. begin
  15. if (x<=l)and(r<=y) then exit(tree[k]); mid:=(l+r) >> 1;
  16. if x<=mid then inc(Query,Query(l,mid,k << 1,x,y));
  17. if y>mid then inc(Query,Query(mid+1,r,k << 1+1,x,y));
  18. end;
  19. procedure Change(l,r,k,key,add:longint);
  20. var mid:longint;
  21. begin
  22. if l=r then begin inc(tree[k],add); exit; end; mid:=(l+r) >> 1;
  23. if key<=mid then Change(l,mid,k << 1,key,add) else Change(mid+1,r,k << 1+1,key,add);
  24. tree[k]:=tree[k << 1]+tree[k << 1+1];
  25. end;
  26. procedure AnswerMaker(dis,x,fa:longint);
  27. var i:longint;
  28. begin
  29. if x=-1 then exit; i:=cnt[x];
  30. while i<>-1 do
  31. begin
  32. if reach[i]<>fa then
  33. begin
  34. if dis+value[i]<=k then inc(ans);
  35. inc(ans,Query(1,n,1,0,k-(dis+value[i]))); AnswerMaker(dis+value[i],reach[i],x);
  36. Change(1,n,1,dis+value[i],1);
  37. end;
  38. end;
  39. end;
  40. procedure AnswerSweeper(dis,x,fa:longint);
  41. var i:longint;
  42. begin
  43. if x=-1 then exit; i:=cnt[x];
  44. while i<>-1 do
  45. begin
  46. if reach[i]<>fa then
  47. begin
  48. if dis+value[i]<=k then inc(ans);
  49. AnswerMaker(dis+value[i],reach[i],x);
  50. Change(1,n,1,dis+value[i],-1);
  51. end;
  52. end;
  53. end;
  54. procedure SizeMaker(x,fa:longint);
  55. var i:longint;
  56. begin
  57. if x=-1 then exit; i:=cnt[x];
  58. if i=-1 then begin size[x]:=1; exit; end;
  59. while i<>-1 do
  60. begin
  61. if reach[i]<>fa then begin SizeMaker(reach[i],x); inc(size[x],size[reach[i]]); end;
  62. i:=next[i];
  63. end;
  64. end;
  65. function BanlancedPoint(standard,x,fa:longint):longint;
  66. var i:longint;
  67. begin
  68. if x=-1 then exit; i:=cnt[x]; BanlancedPoint:=0;
  69. if abs(size[x]-standard)<=2 then exit(x) else
  70. begin
  71. while i<>-1 do
  72. begin
  73. if reach[i]<>fa then BanlancedPoint:=BanlancedPoint(standard,reach[i],x);
  74. if BanlancedPoint<>0 then exit; i:=next[i];
  75. end;
  76. end;
  77. end;
  78. procedure Conquer(x:longint);
  79. var i:longint;
  80. begin
  81. if x=-1 then exit; SizeMaker(x,x); i:=cnt[x];
  82. while i<>-1 do begin AnswerMaker(0,reach[i],reach[i]); i:=next[i]; end; i:=cnt[x];
  83. while i<>-1 do begin AnswerSweeper(0,reach[i],reach[i]); i:=next[i]; end; i:=cnt[x];
  84. while i<>-1 do begin Conquer(BanlancedPoint(size[x] >> 1,reach[i],reach[i])); reach[i]:=-1; i:=next[i]; end;
  85. end;
  86. begin
  87. filldword(cnt,sizeof(cnt) >> 2,maxlongint << 1+1); read(n,k);
  88. for i:=1 to n do begin read(a,b,c); Link(a,b,c); end;
  89. Conquer(root); writeln(ans);
  90. end.
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注