这道题是楼教主《男人八题》中的一题,算法:树的分治。
看到题目时很容易想到直接Dfs,但那样的话时间复杂度会高达O(n^2)!对于n<=40000的数据来说根本无法承受。所以,必须考虑分治的思想。
怎么分治呢?
树的重心!
至于树的重心,不熟悉的OIer可以做掉POJ1655,或者NOI2011 Day2的第一题来练手,这两道题要求的就是树的重心。至于pascal语言的ACMer可以考虑编译开关,OIer最好不要加编译开关,练一练非递归手写栈也是不错的。
基本思路:
1、把这棵无根树以1为根节点,使其变成一棵有根树。
2、对于每棵现在要处理的树,进行如下处理:
(1)遍历这棵树,找到所有一端点为根,路径长度<=k的路径总数
(2)通过(1)求出的结果求和计算出所有长度<=k的的路径总数
(3)去重:也就是删去(2)中计算有重合的路径部分
(4)找到这棵子树的重心,递归处理这棵子树,也就是重复步骤2
3、统计答案并输出
总体来说,这题难度不小,可是把它做掉的感觉也是很cool的。最重要的是,树的分治思想在这道题中体现得淋漓尽致,这是这道题的借鉴意义所在。
POJ1741也是这个思想,可以拿来练手。
Program POJ1987;//By_Poetshy
Const
maxn=40005;
Var
i,j,k,m,n,d,kol :Longint;
sum,root,min,tot,ans :Longint;
pre,other,last,data :Array[0..maxn*2]of Longint;
seq :Array[0..maxn*2]of Longint;
size,f :Array[0..maxn*2]of Longint;
v :Array[0..maxn]of Boolean;
Procedure Getroot(i:Longint);
var j,k,w:Longint;
begin
j:=last[i];
size[i]:=1;
v[i]:=true;
w:=0;
while j<>0 do
begin
k:=other[j];
if not v[k] then
begin
Getroot(k);
inc(size[i],size[k]);
if size[k]>w then w:=size[k];
end;
j:=pre[j];
end;
if sum-size[i]>w then w:=sum-size[i];
if w<min then
begin
min:=w;
root:=i;
end;
v[i]:=false;
end;
Procedure Count(i:Longint);
var j,k:Longint;
begin
v[i]:=true;
j:=last[i];
inc(sum);
while j<>0 do
begin
k:=other[j];
if not v[k] then Count(k);
j:=pre[j];
end;
v[i]:=false;
end;
Procedure Deal(i,d:Longint);
var j,k:Longint;
begin
if d<=kol then
begin
inc(tot);
seq[tot]:=d;
end else exit;
v[i]:=true;
j:=last[i];
while j<>0 do
begin
k:=other[j];
if not v[k] then Deal(k,d+data[j]);
j:=pre[j];
end;
v[i]:=false;
end;
Procedure Qsort(l,r:Longint);
var i,j,k,temp:Longint;
begin
if l>=r then exit;
i:=l;j:=r;k:=seq[(i+j)>>1];
repeat
while seq[i]<k do inc(i);
while seq[j]>k do dec(j);
if i<=j then
begin
temp:=seq[i];
seq[i]:=seq[j];
seq[j]:=temp;
inc(i);dec(j);
end;
until i>j;
if i<r then Qsort(i,r);
if l<j then Qsort(l,j);
end;
Function Reduce(l,r:Longint):Longint;
var i,j:Longint;
begin
Reduce:=0;
j:=r;
for i:=l to r do
begin
if i=j then exit;
while (i<j)and(seq[i]+seq[j]>kol)do dec(j);
if i=j then exit;
inc(Reduce,j-i);
end;
end;
Procedure Dfs(i:Longint);
var y,j,k,la:Longint;
begin
sum:=0;tot:=1;seq[tot]:=0;
Count(i);
if sum=1 then exit;
min:=sum;
Getroot(i);
i:=root;j:=last[i];
v[i]:=true;
while j<>0 do
begin
k:=other[j];
if not v[k] then
begin
la:=tot+1;
Deal(k,data[j]);
Qsort(la,tot);
dec(f[i],Reduce(la,tot));
end;
j:=pre[j];
end;
Qsort(1,tot);
inc(f[i],Reduce(1,tot));
j:=last[i];
while j<>0 do
begin
k:=other[j];
if not v[k] then Dfs(k);
j:=pre[j];
end;
v[i]:=false;
end;
BEGIN
readln(n);
for i:=1 to n-1 do
begin
readln(m,j,d);
inc(k);pre[k]:=last[m];last[m]:=k;other[k]:=j;data[k]:=d;
inc(k);pre[k]:=last[j];last[j]:=k;other[k]:=m;data[k]:=d;
end;
readln(kol);
Dfs(1);
ans:=0;
for i:=1 to n do
inc(ans,f[i]);
writeln(ans);
END.