思路
点分治
二分小于等于k的位置即可
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int middis[40010],midcnt,n,k,u[40010<<1],v[40010<<1],w[40010<<1],cnt,fir[40010],nxt[40010<<1],sz[40100],f[40100],root,vis[40100],Siz;
long long ans=0;
void addedge(int ui,int vi,int wi){
++cnt;
u[cnt]=ui;
v[cnt]=vi;
w[cnt]=wi;
nxt[cnt]=fir[ui];
fir[ui]=cnt;
}
void findroot(int u,int fa){
f[u]=1;
sz[u]=1;
for(int i=fir[u];i;i=nxt[i]){
if(v[i]==fa||vis[v[i]])
continue;
findroot(v[i],u);
sz[u]+=sz[v[i]];
f[u]=max(f[u],sz[v[i]]);
}
f[u]=max(Siz-f[u],f[u]);
if(f[root]>f[u])
root=u;
}
void getdis(int u,int d,int fa){
middis[++midcnt]=d;
for(int i=fir[u];i;i=nxt[i]){
if(v[i]==fa||vis[v[i]])
continue;
getdis(v[i],d+w[i],u);
}
}
int look(int l,int k){
int ans=0,r=midcnt;
while(l<=r){
int mid=(l+r)>>1;
if(middis[mid]<=k)
ans=mid,l=mid+1;
else
r=mid-1;
}
}
int solve(int u,int d,int fa){
midcnt=0;
getdis(u,d,fa);
sort(middis+1,middis+midcnt+1);
int l=1,ans=0;
// ans+=look(1,k);
while(l<midcnt&&k-middis[l]>=middis[l]){
int lx=look(l+1,k-middis[l]);
if(lx>l)
ans+=lx-l-1;
l++;
}
return ans;
}
void divide(int u){
// printf("%d
",u);
// getchar();
vis[u]=true;
ans+=solve(u,0,0);
// printf("ans=%d
",ans);
for(int i=fir[u];i;i=nxt[i]){
if(vis[v[i]])
continue;
ans-=solve(v[i],w[i],u);
root=0;
Siz=sz[v[i]];
findroot(v[i],u);
divide(root);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n-1;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
scanf("%d",&k);
Siz=n;
f[0]=0x3f3f3f3f;
findroot(1,0);
divide(root);
printf("%d
",ans);
return 0;
}