这道题是楼教主《男人八题》中的一题,算法:树的分治。

看到题目时很容易想到直接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也是这个思想,可以拿来练手。

 

CODE

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.