题目:求一棵树上路径长度小于k的路径条数。
思路:这是LTC的男人八题里比较简单的一道。首先如果不是树,而是链的话,我们 可以想到一种分治算法(当然链的情况不分治更快),就是对于一个中点,对答案有贡献的要么是跨越中点的路径,要么是两边的路径,那么每次从中点分开,进行 分治的话复杂度是O(nlogn),对于这个树上的情况思路也是一样的,但是树上的分治有个比较特殊的地方是这个中点不太好找,需要跑一次dfs。然后对 每个分开的子树递归计算。我的实现总共用了5个递归,似乎可以少用一个(算子树的节点数目的时候),但是没想清楚怎么去,就索性直接又dfs了一遍。
另外,除了这种点分治,还可以使用边分治,但是边分治有一种难以避免的使复杂度大大增加的情况(处理方法似乎比较复杂),所以树分治的首选还是点分治。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind * http://www.cnblogs.com/Cw-trip/ * 蒟蒻只能做几个水题。。 */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps 0.00000001 #define IINF (1<<29) #define LINF (1ll<<59) #define INF 1000000000 typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=2e4+300; struct EDGE{ int to,d; }; vector<int> G[maxn]; EDGE es[maxn]; int eh; int center,mins; bool vis[maxn]; vector<int> dis; int n,k; int cnt; int getCenter(int v,int f){ int ssum=0,maxs=0; for(int i=0;i<G[v].size();i++){ int e=G[v][i]; int u=es[e].to; if(vis[u]||u==f) continue; int aa=getCenter(u,v); if(aa>maxs) maxs=aa; ssum+=aa; } if(max(maxs,cnt-ssum-1)<mins){ center=v; mins=max(maxs,cnt-ssum-1); } return ssum+1; } void dfs(int v,int fore,int f){ dis.pb(fore); for(int i=0;i<G[v].size();i++){ int e=G[v][i]; int u=es[e].to; if(vis[u]||u==f) continue; dfs(u,fore+es[e].d,v); } } void cont(int v,int f){ cnt++; for(int i=0;i<G[v].size();i++){ int e=G[v][i]; int u=es[e].to; if(vis[u]||u==f) continue; cont(u,v); } } int cul(int v,int fore){ int ans=0; dis.clear(); dfs(v,fore,-1); sort(dis.begin(),dis.end()); int p=0,q=dis.size()-1; while(p<=q){ while(p<=q&&dis[q]+dis[p]>k) q--; if(p>q) break; ans+=q-p; p++; } return ans; } int solve(int v){ vis[v]=1; int ans=0; ans+=cul(v,0); for(int i=0;i<G[v].size();i++){ int e=G[v][i]; int u=es[e].to; if(vis[u]) continue; ans-=cul(u,es[e].d); mins=1e8; cnt=0; cont(u,-1); getCenter(u,-1); ans+=solve(center); } return ans; } void addedge(int from,int to,int d){ es[eh].to=to,es[eh].d=d; G[from].pb(eh++); es[eh].to=from,es[eh].d=d; G[to].pb(eh++); } void init(){ eh=0; for(int i=0;i<=n;i++) G[i].clear(); memset(vis,0,sizeof vis); dis.clear(); } int main(){ freopen("/home/files/CppFiles/in","r",stdin); //freopen("defense.in","r",stdin); //freopen("defense.out","w",stdout); while(cin>>n>>k){ if(n==0&&k==0) break; init(); for(int i=0;i<n-1;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); } mins=1e9; dfs(1,0,-1); cnt=0; cont(1,-1); getCenter(1,-1); cout<<solve(center)<<endl; } return 0; }