题目大意:有一颗由n个点组成的树,问树上两点间距离小于等于k的点对有多少对
输入:多组数据输入。每组数据第1行n,k,接下来n-1行,u,v,l表示点u与点v之间有一条长为l的边
输出:点对个数
/* 借此题说说对点分治的认识,点分治就是将一棵树分为几部分,使得最大的一部分的点数最小,也就是找树的重心 对于经过重心的, 1、统计出过重心的所有点的满足条件的数目=ans1 2、对于每棵子树,统计一遍自己内部满足条件的数目=ans2 ans=ans1-所有的ans2 对于不经过重心的,继续递归 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define INF 0x7fffffff #define maxn 10010 struct node{int to,v,pre;}e[maxn*2]; int n,num,k,root,sum,ans,head[maxn],f[maxn]; int vis[maxn],son[maxn],d[maxn],dep[maxn]; void Insert(int from,int to,int v){ e[++num].to=to; e[num].v=v; e[num].pre=head[from]; head[from]=num; } void getroot(int x,int fa){ son[x]=1;f[x]=0; for(int i=head[x];i;i=e[i].pre){ int to=e[i].to; if(to==fa||vis[to])continue; getroot(to,x); son[x]+=son[to]; f[x]=max(f[x],son[to]); } f[x]=max(f[x],sum-son[x]); if(f[x]<f[root])root=x; } void getdeep(int x,int fa){ dep[++dep[0]]=d[x]; for(int i=head[x];i;i=e[i].pre){ int to=e[i].to; if(to==fa||vis[to])continue; d[to]=d[x]+e[i].v; getdeep(to,x); } } int cal(int x,int v){ d[x]=v;dep[0]=0; getdeep(x,0); sort(dep+1,dep+dep[0]+1); int l=1,r=dep[0],sum=0; while(l<r){ if(dep[l]+dep[r]<=k){sum+=r-l;l++;} else r--; } return sum; } void solve(int x){ ans+=cal(x,0); vis[x]=1; for(int i=head[x];i;i=e[i].pre){ int to=e[i].to; if(vis[to])continue; ans-=cal(to,e[i].v); sum=son[to]; root=0; getroot(to,0); solve(root); } } int main(){ //freopen("Cola.txt","r",stdin); while(1){ ans=0,root=0,num=0; memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); scanf("%d%d",&n,&k); if(n==0&&k==0)break; for(int i=1;i<=n-1;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); Insert(x,y,z);Insert(y,x,z); } f[0]=INF;sum=n; getroot(1,0); solve(root); printf("%d\n",ans); } return 0; }