Partition considered point, for a sub-tree, the root obtains the distance to each point and sorting, dual scan pointer, but this path will be the same from a son count up, and then do it again for each son, Save go to.
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; typedef long long ll; const int N=40005; char rB[1<<21],*S,*T; inline char gc(){return S==T&&(T=(S=rB)+fread(rB,1,1<<21,stdin),S==T)?EOF:*S++;} inline int rd(){ char c=gc(); while(c<48||c>57)c=gc(); int x=c&15; for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } int G[N],to[N<<1],w[N<<1],nxt[N<<1],cnt=0,sz[N],f[N],sum,rt,d[N],t[N],tot,k; ll ans=0ll; bool vis[N],inq[N]; queue<int> Q; inline void add(int u,int v,int c){ to[++cnt]=v;w[cnt]=c;nxt[cnt]=G[u];G[u]=cnt; to[++cnt]=u;w[cnt]=c;nxt[cnt]=G[v];G[v]=cnt; } void GETRT ( int U, int FA) { // point focus search partition int I, V; sz[u]=1;f[u]=0; for(i=G[u];i;i=nxt[i])if(!vis[v=to[i]]&&v!=fa){ getrt (v, u); c [u] + = c [v]; f[u]=max(f[u],sz[v]); } f[u]=max(f[u],sum-sz[u]); if(f[u]<f[rt])rt=u; } ll inline calc ( you and, you k) { you i, h, v, l, r; ll ans=0ll; memset(inq,0,sizeof(inq)); inq[u]=1;t[tot=1]=d[u]=0;Q.push(u); while(!Q.empty()){ H = Q.front (); Q.pop (); for (I = G [H]; I; I = NXT [I]) IF (VIS [to V = [I]] && INQ [V]!! && (D [V] D = [H] + W [I]) <= k) { // is greater than the distance k is not contribute answers, without saving T [TOT ++] = D [V]; inq [v] = 1 ; Q.push(v); } } sort(t+1,t+tot+1); for(l=1,r=tot;l<=r;++l){ while(l<=r&&t[l]+t[r]>k)--r; if(l>r)break; years + = r l; } return years; } void solve(int u){ int i,v; vis[u]=1;ans+=calc(u,k); for(i=G[u];i;i=nxt[i])if(!vis[v=to[i]]){ ans - calc = (v, k (in [i] << 1 )); sum=sz[v];rt=0;getrt(v,u); solve(rt); } } int main(){ int n=f[0]=sum=rd(),i,u,v,c; for(i=1;i<n;++i){ u = rd (); v = rd (); c = rd (); add(u,v,c); } k = rd (); getrt(1,0);solve(rt); printf("%lld",ans); return 0; }