树分治策略,
本题目直接爆o(n^2)肯定会超时,采取分治策略,每次dfs子树都要先找到重心,这样深度不超过logn层
然后鬼每一个重心只统计过该点的不超过k的路径数,要统计该值首先要先得到所有子节点到该点的距离,然后排序,排序之后可用o(n)的相向搜索得到;
需注意必须再减去在同一子树中两点构成的小于等于k的路径;因为这条路径不合法;总复杂度nlognlogn
这里给出复杂度证明:
第一层为nlogn
假设第二层为有三颗子树其数量记为n1,n2,n3( n1+n2+n3=n-1 ) 则在该层耗时 n1logn1 + n2logn2 + n3logn3 <n1logn++ n2logn+ n3logn < nlogn
所以总层数为logn层 所以总共耗时 t < n logn*logn
#include <cstdio> #include <map> #include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; struct node{ int x,y; node(int x=0,int y=0):x(x),y(y){} bool operator <(const node& rhs)const{ return x<rhs.x || x==rhs.x&&y<rhs.y; } }; const int maxn = 10110; vector<node> G[maxn]; int focus,n,MIN,pre[maxn],K,nown; int get_focus(int u,int f){ int tot = 1,min_=0; for(int i=0;i<G[u].size();i++){ if(pre[G[u][i].x]) continue; if(G[u][i].x==f) continue; int temp = get_focus(G[u][i].x,u); tot+=temp; min_=max(min_,temp); } min_=max(min_,nown-tot); if(min_ < MIN){ MIN = min_; focus=u; } return tot; } int Get_focus(int u,int f,int te){ nown = te; MIN = n; get_focus(u,f); return focus; } vector<int> dis; int res,CNT; void get_dis(int u,int f,int add){ dis.push_back(add); CNT++; for(int i=0;i<G[u].size();i++){ if(pre[G[u][i].x]) continue; if(G[u][i].x==f) continue; get_dis(G[u][i].x,u,add+G[u][i].y); } } int solve(int u,int f,int add){ dis.clear(); get_dis(u,f,add); sort(dis.begin(),dis.end()); int num = 0; for(int i=0,j=dis.size()-1;i<j;i++){ while(j>i&&dis[j] + dis[i]>K) j--; if(i<j) num+=j-i; } return num; } void dfs(int u,int f){ res+=solve(u,f,0); pre[u] = 1; for(int i=0;i<G[u].size();i++){ if(pre[G[u][i].x]) continue; if(G[u][i].x==f) continue; CNT = 0; res-=solve(G[u][i].x,u,G[u][i].y); Get_focus(G[u][i].x,u,CNT); dfs(focus,-1); } } int main() { while(scanf("%d %d",&n,&K)==2){ if(!n&&!K) break; for(int i=1;i<=n;i++) G[i].clear(); memset(pre,0,sizeof(pre)); for(int i=1;i<n;i++){ int x,y,z; scanf("%d %d %d",&x,&y,&z); G[x].push_back(node(y,z)); G[y].push_back(node(x,z)); } Get_focus(1,-1,n); res=0; dfs(focus,-1); printf("%d\n",res); } return 0; } /* 5 1 1 2 1 2 3 1 3 4 1 4 5 1 */