http://poj.org/userstatus?user_id=fzsz_chy
找重心作根,统计通过重心的路径数量
删根形成若干子树,再做类似操作.
#include<cstdio> #include<algorithm> #define FOR(i,s,t) for(register int i=s;i<=t;++i) #define ROF(i,s,t) for(register int i=s;i>=t;--i) #define VIS(now) for(register int e=las[now];e;e=nxt[e]) using std::sort; typedef long long ll; ll ans; int n,k,tot; const int N=10011; int sz[N],vis[N]; int dis[N]; int las[N],nxt[N<<1],w[N<<1],f[N],to[N<<1],son[N<<1]; inline int max(int a,int b){ return a>b?a:b; } inline void add(int x,int y,int z){ nxt[++tot]=las[x];las[x]=tot;w[tot]=z;to[tot]=y; } inline int find(int rt){ static int qn,que[N]; que[qn=1]=rt,f[rt]=0; int v,u,mx=n,G=0; FOR(ql,1,qn){ sz[u=que[ql]]=1,son[u]=0; VIS(u) if(!vis[v=to[e]]&&v!=f[u]){ f[v]=u; que[++qn]=v; } } ROF(ql,qn,1){ u=que[ql],v=f[u]; if(qn-sz[u]>son[u])son[u]=qn-sz[u]; if(son[u]<mx)G=u,mx=son[u]; if(!v)break; sz[v]+=sz[u]; if(sz[u]>son[v])son[v]=sz[u]; } return G; } inline ll calc(int rt,int L){ ll cnt=0; static int qn,que[N],d[N]; int u,v,d_n=0; que[qn=1]=rt,dis[rt]=L,f[rt]=0; FOR(ql,1,qn){ d[d_n++]=dis[u=que[ql]]; VIS(u) if(!vis[v=to[e]]&&v!=f[u]) f[v]=u,dis[v]=dis[u]+w[e],que[++qn]=v; } sort(d,d+d_n); register int l=0,r=d_n-1; while(l<r) d[l]+d[r]<=k?cnt+=r-l++:--r; return cnt; } inline void dfs(int x){ int G=find(x); vis[G]=1; ans+=calc(G,0); VIS(G) if(!vis[to[e]]) ans-=calc(to[e],w[e]); VIS(G) if(!vis[to[e]]) dfs(to[e]); } int x,y,z; int main(){ while(~scanf("%d%d",&n,&k)){ ans=0; if(!n||!k)return 0; FOR(i,1,n) las[i]=vis[i]=0; tot=0; FOR(i,2,n){ scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } dfs(1); printf("%lld ",ans); } return 0; }