POJ1751 Tree 树分治
分析:每次找重心可以发现最多n层,每层复杂度是O(nlogn) 总体时间复杂度是O(nlog^2n)
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <stdlib.h> using namespace std; typedef long long LL; const int N=1e4+5; int head[N],tot,n,k,ret,cnt,sz[N],rt,p,dis[N],mx[N]; bool vis[N]; struct Edge{ int v,w,next; }edge[N<<1]; void add(int u,int v,int w){ edge[tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } void getsz(int u,int f){ sz[u]=1;mx[u]=0; for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].v;if(v==f||vis[v])continue; getsz(v,u);sz[u]+=sz[v]; if(sz[v]>mx[u])mx[u]=sz[v]; } } void getroot(int tp,int u,int f){ mx[u]=max(mx[u],sz[tp]-sz[u]); if(mx[u]<cnt)cnt=mx[u],rt=u; for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].v;if(v==f||vis[v])continue; getroot(tp,v,u); } } void getdis(int u,int f,int d){ dis[++p]=d; for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].v;if(v==f||vis[v])continue; getdis(v,u,d+edge[i].w); } } int cal(int u,int d){ int ans=0; p=0; getdis(u,-1,d); sort(dis+1,dis+1+p); for(int i=1,j=p;i<j;++i){ while(dis[i]+dis[j]>k&&i<j)--j; ans+=j-i; } return ans; } void dfs(int u){ cnt=n;getsz(u,-1);getroot(u,u,-1); ret+=cal(rt,0);vis[rt]=true; for(int i=head[rt];~i;i=edge[i].next){ int v=edge[i].v;if(vis[v])continue; ret-=cal(v,edge[i].w); dfs(v); } } int main(){ while(~scanf("%d%d",&n,&k),n&&k){ for(int i=1;i<=n;++i)head[i]=-1,vis[i]=false; ret=tot=0; for(int i=1;i<n;++i){ int u,v,w;scanf("%d%d%d",&u,&v,&w); add(u,v,w);add(v,u,w); } dfs(1); printf("%d\n",ret); } return 0; }