【分析】
点分治。
考虑当前子树中,一条路径要么经过根节点,要么在一棵子树中,在子树中的可以递归处理,所以当前统计时需要减掉。
推荐看09年漆子超论文。
【代码】
#include <cstdio>
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#define N 10005
#define M 20005
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pa;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,K,cnt,sum,ans,root;
int b[M],p[N],nextedge[M],w[M];
int f[N],d[N],deep[N],sz[N];
bool flag[N];
void Add(int x,int y,int z)
{
cnt++;
b[cnt]=y;
nextedge[cnt]=p[x];
p[x]=cnt;
w[cnt]=z;
}
void Anode(int x,int y,int z){
Add(x,y,z);Add(y,x,z);
}
void getroot(int x,int fa)
{
sz[x]=1;f[x]=0;
for(int i=p[x];i;i=nextedge[i])
{
int v=b[i];
if(v==fa||flag[v]) continue;
getroot(v,x);
sz[x]+=sz[v];
f[x]=max(f[x],sz[v]);
}
f[x]=max(f[x],sum-sz[x]);
if(f[x]<f[root]) root=x;
}
void getdeep(int x,int fa)
{
deep[++deep[0]]=d[x];
for(int i=p[x];i;i=nextedge[i])
{
int v=b[i];
if(v==fa||flag[v]) continue;
d[v]=d[x]+w[i];
getdeep(v,x);
}
}
int Cal(int x,int now)
{
d[x]=now;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 work(int x)
{
ans+=Cal(x,0);
flag[x]=1;
for(int i=p[x];i;i=nextedge[i])
{
int v=b[i];
if(flag[v]) continue;
ans-=Cal(v,w[i]);
sum=sz[v];
root=0;
getroot(v,root);
work(root);
}
}
int main()
{
while(1)
{
n=read();K=read();
if(!n) break;
for(int i=1;i<=n;i++) p[i]=flag[i]=0;
cnt=ans=root=0;
for(int i=1;i<n;i++)
{
static int x,y,z;
x=read(),y=read(),z=read();
Anode(x,y,z);
}
sum=n;f[0]=INF;
getroot(1,0);
work(root);
printf("%d\n",ans);
}
return 0;
}