poj1741
这是点分治的入门题。
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
int const N=1e4+10;
int sz[N],n,k;
struct edge{
int to,nt,w;
}e[N<<1];
int cnt,h[N],ans,vis[N],d[N],son,dd[N];
void add(int a,int b,int c){
e[++cnt].to=b;
e[cnt].w=c;
e[cnt].nt=h[a];
h[a]=cnt;
}
int dfs(int x,int fa,int dist){
int res=1;d[++d[0]]=dist;
for(int i=h[x];i;i=e[i].nt){
int v=e[i].to;
if(v==fa || vis[v]) continue;
res+=dfs(v,x,dist+e[i].w);
}
return res;
}
void find(int x,int fa,int sum){
sz[x]=1;
int mx=0;
for(int i=h[x];i;i=e[i].nt){
int v=e[i].to;
if(v==fa || vis[v]) continue;
find(v,x,sum);
mx=max(mx,sz[v]);
sz[x]+=sz[v];
}
mx=max(mx,sum-sz[x]);
if(mx<=sum/2) son=x;
}
void solve(int x){
dd[0]=0;
for(int i=h[x];i;i=e[i].nt){
int v=e[i].to;
if(vis[v]) continue;
d[0]=0;
dfs(v,x,e[i].w);
sort(d+1,d+d[0]+1);
for(int j=1;j<=d[0];j++)
if(d[j]<=k) ans++;
int q=d[0];
for(int j=1;j<=d[0];j++) {
while (j<q && d[j]+d[q]>k) q--;
if(q>j) ans-=(q-j);
}
for(int j=1;j<=d[0];j++)
dd[++dd[0]]=d[j];
}
sort(dd+1,dd+dd[0]+1);
int q=dd[0];
for(int i=1;i<=dd[0];i++){
while (i<q && dd[i]+dd[q]>k) q--;
if(q>i) ans+=(q-i);
}
for(int i=h[x];i;i=e[i].nt){
int v=e[i].to;
if(vis[v]) continue;
int s=dfs(v,x,e[i].w);
find(v,x,s);
vis[son]=1;
solve(son);
}
}
int main(){
while (scanf("%d%d",&n,&k)==2){
if(n==0 && k==0)
break;
cnt=0;
memset(h,0,sizeof(h));
memset(vis,0,sizeof(vis));
for(int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
ans=0;
int s=dfs(1,1,0);
find(1,1,s);
vis[son]=1;
solve(son);
printf("%d\n",ans);
}
return 0;
}
```c++