传送门biu~
另一种点分治的写法。求出所有路径,再用容斥减去在同一棵子树中的路径。
#include<bits/stdc++.h>
using namespace std;
int n,k,center,len,ans;
int fa[40005],siz[40005],s[40005],d[40005];
int head[40005],nex[80005],to[80005],val[80005],tp;
bool b[40005];
inline void add(int x,int y,int z){
nex[++tp]=head[x];
head[x]=tp;
to[tp]=y;
val[tp]=z;
}
void get_tree_center(int x,int father,int tot){
fa[x]=father;
siz[x]=1;
bool flag=true;
for(int i=head[x];i;i=nex[i]){
if(to[i]==father || b[to[i]]) continue;
get_tree_center(to[i],x,tot);
if(siz[to[i]]>tot/2) flag=false;
siz[x]+=siz[to[i]];
}
if(tot-siz[x]>tot/2) flag=false;
if(flag) center=x;
}
void dfs(int x,int father){
s[++len]=d[x];
for(int i=head[x];i;i=nex[i]){
if(to[i]==father || b[to[i]]) continue;
d[to[i]]=d[x]+val[i];
dfs(to[i],x);
}
}
int calc(int x,int v){
d[x]=v;len=0;
dfs(x,0);
sort(s+1,s+len+1);
int R=len,re=0;
for(int i=1;i<=len;++i){
while(s[R]+s[i]>k && R>i) --R;
if(R<=i) break;
re+=R-i;
}
return re;
}
void tree_divide(int x){
int tot=siz[x];
get_tree_center(x,0,tot);
x=center;
if(fa[x]) siz[fa[x]]=tot-siz[x];
ans+=calc(x,0);
b[x]=1;
for(int i=head[x];i;i=nex[i]){
if(b[to[i]]) continue;
ans-=calc(to[i],val[i]);
tree_divide(to[i]);
}
}
int main(){
scanf("%d",&n);
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);
}
scanf("%d",&k);
siz[1]=n;
tree_divide(1);
printf("%d",ans);
return 0;
}