POJ - 1741 Tree(点分治)
题意:给你一颗树,然后问你有多少小于k的路径
思路:点分治入门题,网上有很多关于点分治的博客,我也看了很久的代码,想了很久。
大概点分治就是一种通过不断找树的重心来降低复杂度的一种算法,因为数据范围很小,看其他聚聚的博客说一般点分治的题,数据范围都暗示1e4;
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=10005; struct edge { int to,next,w; }a[maxn<<1]; int n,m,k,head[maxn],cnt; int root,sum,vis[maxn],sz[maxn]; int f[maxn],dep[maxn],stk[maxn],top; int ans; void addedge(int u,int v,int w) { a[++cnt].to=v; a[cnt].next=head[u]; a[cnt].w=w; head[u]=cnt; } void getroot(int u,int fa) { sz[u]=1;f[u]=0; for(int e=head[u];e;e=a[e].next){ int v=a[e].to; if(v==fa||vis[v])continue; getroot(v,u); sz[u]+=sz[v]; f[u]=max(f[u],sz[v]); } f[u]=max(f[u],sum-sz[u]); if(f[u]<f[root])root=u; } void getdep(int u,int fa) { stk[++top]=dep[u]; for(int e=head[u];e;e=a[e].next){ int v=a[e].to; if(v==fa||vis[v])continue; dep[v]=dep[u]+a[e].w; getdep(v,u); } } int calc(int u,int d0) { top=0;dep[u]=d0; getdep(u,0); sort(stk+1,stk+top+1); int l=1,r=top,res=0; while(l<r){ if(stk[l]+stk[r]<=k)res+=r-l,l++; else r--; } return res; } void solve(int u) { ans+=calc(u,0); vis[u]=1; for(int e=head[u];e;e=a[e].next){ int v=a[e].to; if(vis[v])continue; ans-=calc(v,a[e].w); sum=sz[v];root=0; getroot(v,0); solve(root); } } int main() { while(~scanf("%d%d",&n,&k)){ if(n==0&&k==0)break; memset(head,0,sizeof(head)); memset(vis,0,sizeof(vis)); cnt=0;ans=0; for(int i=1;i<n;++i){ int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } root=0;sum=f[0]=n; getroot(1,0); solve(root); printf("%d\n",ans); } return 0; }