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.
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.
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的点对有多少个。
一道点分治题。
一个重要的问题是,为了防止退化,所以每次都要找到树的重心然后分治下去,所谓重心,就是删掉此结点后,剩下的结点最多的树结点个数最小。
题目大意:求树上距离小于等于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;
}