点分治板子POJ1741
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\n",ans);
}
return 0;
}

浙公网安备 33010602011771号