F - %yclA
给出一棵树,询问有多少个点路径 <=k;
考虑点分治:
点分治:
解决大规模图上路径问题。
算法流程:
考虑一个树上的路径,只有两种情况,经过根和不经过根,
1 . 经过根的路径可以直接判断 dis(u,v)=d(u)+d(v) ;
2 . 不经过根就找到那个根继续遍历分治下去求解。
找根的过程 : 如果链状的树,会直接退化到O(n^2) 因此每次对重心遍历,保证复杂度
对于每一个节点,统计穿过他的合法解,即 ans+=cal(rt,0);
但这样会有重复情况,在继续统计子树会出现问题,
因此 ans-=cal(v,w);

#include <cstdio> #include <cstring> #include <iostream> #include <vector> #include <algorithm> using namespace std; #define pb push_back const int N=1e4+5; struct edge{int v,w,next;}e[N*10]; int ans,n,K,ecnt,root,Max; int head[N],size[N],maxv[N]; vector<int>dis; bool vis[N]; void add(int u,int v,int w){ e[ecnt].v=v;e[ecnt].w=w;e[ecnt].next=head[u];head[u]=ecnt++; } void init(){ memset(head,-1,sizeof head); memset(vis,0,sizeof vis); ecnt=ans=0; } void dfs_size(int u,int fa){ size[u]=1;maxv[u]=0; for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(vis[v]||v==fa)continue; dfs_size(v,u); size[u]+=size[v]; maxv[u]=max(maxv[u],size[v]); } } void dfs_root(int r,int u,int fa){ maxv[u]=max(maxv[u],size[r]-size[u]); if(maxv[u]<Max){ Max=maxv[u]; root=u; } for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa||vis[v])continue; dfs_root(r,v,u); } } void dfs_dis(int u,int fa,int dir){ dis.push_back(dir); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v,w=e[i].w; if(vis[v]||v==fa)continue; dfs_dis(v,u,dir+w); } } int cal(int rt,int d){ dis.clear(); dfs_dis(rt,-1,d); sort(dis.begin(),dis.end()); int i=0,j=dis.size()-1,cur=0; while(i<j){ while(dis[i]+dis[j]>K&&i<j)j--; cur+=j-i; i++; } return cur; } void DFS(int u){ Max=n; dfs_size(u,-1); dfs_root(u,u,-1); int rt=root; ans+=cal(rt,0); vis[rt]=1; for(int i=head[rt];~i;i=e[i].next){ int v=e[i].v,w=e[i].w; if(vis[v])continue; ans-=cal(v,w); DFS(v); } } int main(){ while(~scanf("%d %d",&n,&K),n+K){ init(); for(int i=1,u,v,w;i<n;i++){ scanf("%d %d %d",&u,&v,&w); add(u,v,w);add(v,u,w); } DFS(1); printf("%d ",ans); } // system("pause"); return 0; } // 5 4 // 1 2 3 // 1 3 1 // 1 4 2 // 3 5 1 // 0 0