Description

Give a tree with n vertices,each edge has a length(positive integer less than 1001).
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.

Input

The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.
The last test case is followed by two zeros.

Output

For each test case output the answer on a single line.

Sample Input

5 4 1 2 3 1 3 1 1 4 2 3 5 1 0 0 

Sample Output

8

Source

LouTiancheng@POJ

题目大意:求树上距离小于等于K的点对有多少个。

一道点分治题。

一个重要的问题是,为了防止退化,所以每次都要找到树的重心然后分治下去,所谓重心,就是删掉此结点后,剩下的结点最多的树结点个数最小。

每次分治,我们首先算出重心,为了计算重心,需要进行两次dfs,第一次把以每个结点为根的子树大小求出来,第二次是从这些结点中找重心

找到重心后,需要统计所有结点到重心的距离,看其中有多少对小于等于K,这里采用的方法就是把所有的距离存在一个数组里,进行快速排序,这是nlogn的,然后用一个经典的相向搜索O(n)时间内解决。但是这些求出来满足小于等于K的里面只有那些路径经过重心的点对才是有效的,也就是说在同一颗子树上的肯定不算数的,所以对每颗子树,把子树内部的满足条件的点对减去。

最后的复杂度是n(logn^2)  其中每次快排是nlogn 而递归的深度为logn

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define INF 0x7f7f7f7f
using namespace std;
int n,K,cnt,sum,ans,root;
int head[10005],deep[10005],d[10005],f[10005],son[10005];
bool vis[10005];
struct data{int to,next,v;}e[20005];
inline int ReadInt()
{
	int f = 1,x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9')
	{
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9')
	{
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

void ins(int u, int v, int w)
{
	e[++ cnt].to = v;
	e[cnt].next = head[u];
	head[u] = cnt;
	e[cnt].v = w;
}
void insert(int u, int v, int w)
{
	ins(u,v,w);
	ins(v,u,w);
}

void getroot(int x, int fa)
{
	son[x] = 1;
	f[x] = 0;
	for(int i = head[x]; i; i = e[i].next)
	{
		if(e[i].to == fa || vis[e[i].to]) continue;
		getroot(e[i].to, x);
		son[x] += son[e[i].to];
		f[x] = max(f[x], son[e[i].to]);
	}
	f[x] = max(f[x],sum - son[x]);
	if(f[x] < f[root]) root = x;
}

void getdeep(int x, int fa)
{
	deep[++ deep[0]] = d[x];
	for(int i = head[x]; i; i = e[i].next)
	{
		if(e[i].to == fa || vis[e[i].to]) continue;
		d[e[i].to] = d[x] + e[i].v;
		getdeep(e[i].to, x);
	}
}

int cal(int x, int y)
{
	d[x] = y;
	deep[0] = 0;
	getdeep(x,0);
	sort(deep + 1, deep + deep[0] + 1);
	int t = 0, l, r;
	for(l = 1, r = deep[0]; l < r; )
	{
		if(deep[l] + deep[r] <= K) { t += r - l; l ++;}
        else r --;
	}
	return t;
}

void Doit(int x)
{
	ans += cal(x, 0);
	vis[x] = 1;
	for(int i = head[x]; i; i = e[i].next)
	{
		if(vis[e[i].to]) continue;
		ans -= cal(e[i].to, e[i].v);
		sum = son[e[i].to];
		root = 0;
		getroot(e[i].to, root);
		Doit(root);
	}
}
int main()
{
	while(1)
	{
		ans = 0;
		root = 0;
		cnt = 0;
		memset(head, 0, sizeof(head));
		memset(vis, 0, sizeof(vis));
		n = ReadInt();
		K = ReadInt();
		if(n == 0 && K == 0) break;
		for(int i = 1; i < n; i ++)
		{
			int u,v,w;
			u = ReadInt();
			v = ReadInt();
			w = ReadInt();
			insert(u,v,w);
		}
		sum = n;
		f[0] = INF;
		getroot(1, 0);
		Doit(root);
		printf("%d\n",ans);
	}
	
	return 0;
}