题意:给一颗n个顶点的树,求最短距离不超过k的顶点对数。
树的分治主要降低时间复杂度的地方就在于对树的分割,划分不均匀很容易使递归的深度退化为O(n),于是我们每次选择一个这样的点作为分割顶点,删除它后使得最大子树的顶点数最小,这样的顶点被称为重心。每次选择重心作为分割点,最大子树的顶点树必然不超过n/2,所以可以保证递归的深度是logN。
然后知道了树的分割后,所要求的顶点对就只有三种类型,第一种是两个点在同一子树上,第二种是一个点为分割点,另一个点在子树上,第三种是两个点分别在不同的子树上,由此分类可知此问题已可以用分治法求解。
第一种情况,可以通过递归得到答案
第二种情况和第三种情况一样,从顶点a到顶点b的路径必然包括分割点,求出每个顶点到分割点的距离,便可得解,对于第二种情况只需加一个与分割点距离为0的点便可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<limits.h>
using namespace std;
const int N = 10005, M = N*2;
int n,k,tot,minn;
int head[N],to[M],val[M],nxt[M];
int fa[N],siz[N],dep[N],l,r;
bool vis[N];
void add_edge(int s,int e,int v){
to[tot]=e;val[tot]=v;
nxt[tot]=head[s];head[s]=tot++;
}
int Cal_size(int s,int f){
fa[s]=f;siz[s]=1;
for(int i=head[s];~i;i=nxt[i])
if(to[i]!=f && !vis[to[i]]) siz[s]+=Cal_size(to[i],s);
return siz[s];
}
void Cal_root(int s,int sum,int &root){
int maxx=sum-siz[s];
for(int i=head[s];~i;i=nxt[i]){
int e=to[i];
if(e==fa[s] || vis[e]) continue;
Cal_root(e,sum,root);
maxx=max(maxx,siz[e]);
}
if(maxx<minn) minn=maxx,root=s;
}
void Find_path(int s,int d,int f){
dep[r++]=d;
for(int i=head[s];~i;i=nxt[i])
if(to[i]!=f && !vis[to[i]])
Find_path(to[i],d+val[i],s);
}
int Get_dep(int a,int b){
sort(dep+a,dep+b);
int ret=0,e=b-1;
for(int i=a;i<b;++i){
if(dep[i]>k) break;
while(e>=a && dep[e]+dep[i]>k) --e;
ret+=e-a+1;if(e>i) ret--;
}
return ret/2;
}
int Solve(int s){
int sum=Cal_size(s,-1),ret=0,root;
minn=INT_MAX;Cal_root(s,sum,root);vis[root]=1;
for(int i=head[root];~i;i=nxt[i])
if(to[i]!=root && !vis[to[i]])
ret+=Solve(to[i]);
l=r=0;
for(int i=head[root];~i;i=nxt[i])
if(to[i]!=root && !vis[to[i]]){
Find_path(to[i],val[i],-1);
ret-=Get_dep(l,r);
l=r;
}
ret+=Get_dep(0,r);
for(int i=0;i<r;++i)
if(dep[i]>k) break;
else ret++;
vis[root]=0;
return ret;
}
int main()
{
int a,b,c;
while(scanf("%d%d",&n,&k),n+k){
tot=0;
memset(head,-1,sizeof (head[0])*(n+1));
memset(vis,false,sizeof (vis[0])*(n+1));
for(int i=1;i<n;++i){
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
}
printf("%d\n",Solve(1));
}
return 0;
}