点分治
树上距离<=k的点对数目
ac:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 20005
using namespace std;
int k,root,sn,tot=0,ans,cnt;
int head[MAXN<<1],to[MAXN<<1],val[MAXN<<1],next1[MAXN<<1],vis[MAXN];
int d[MAXN],deep[MAXN];//路径长度//deep[0]子节点个数
int siz[MAXN],dp[MAXN];
void add(int u ,int v,int w)
{
to[++tot]=v;
val[tot]=w;
next1[tot]=head[u];
head[u]=tot;
}
void getroot(int u,int fa)//计算重心
{
dp[u]=0,siz[u]=1;
for(int i=head[u];i;i=next1[i])
{
int v=to[i];
if(v==fa||vis[v])
continue;
getroot(v,u);
siz[u]+=siz[v];
dp[u]=max(dp[u],siz[v]);
}
dp[u]=max(dp[u],sn-siz[u]);
if(dp[root]>dp[u])
root=u;
}
void getdeep(int x,int fa)//获取子树所有节点与根的距离
{
deep[++cnt]=d[x];
for(int i=head[x];i;i=next1[i])
{
int v=to[i];
if(v==fa||vis[v])
continue;
d[v]=d[x]+val[i];
getdeep(v,x);
}
}
int calc(int x,int now)//计算当前以重心x的子树下,所有情况的答案
{
d[x]=now,cnt=0;
getdeep(x,0);
sort(deep+1,deep+cnt+1);
int sum=0;
for(int i=1,j=cnt;i<j;)
{
if(deep[i]+deep[j]<=k)
sum+=j-i,i++;
else j--;
}
return sum;
}
void work(int x)//以x为重心进行计算
{
vis[x]=1;
ans+=calc(x,0);
for(int i=head[x];i;i=next1[i])
{
int v=to[i];
if(vis[v]==1)
continue;
ans-=calc(v,val[i]);
sn=siz[v];
root=0;
getroot(v,0);
work(root);
}
}
int main()
{
int n,u,v,w;
while(scanf("%d%d",&n,&k))
{
if(n==0&&k==0)
break;
tot=0;
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dp[0]=1e9+7,sn=n;
root=0;
getroot(1,0);
ans=0;
work(root);
printf("%d\n",ans);
}
return 0;
}