1. 程式人生 > >POJ 1741 男人八題——樹分治

POJ 1741 男人八題——樹分治

tor pst def roo 容易 air sizeof ram 出發

Tree
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 23829 Accepted: 7900

Description

Give a tree with n vertices,each edge has a length(positive integer less than 1001).
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.

Input

The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.
The last test case is followed by two zeros.

Output

For each test case output the answer on a single line.

Sample Input

5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0

Sample Output

8

Source

[email protected] 樹分治: 分治很清楚是指分而治之,樹就分成了子樹,但是怎麽分才能是的分才最適合呢? 就像快速排序一樣,也有可能退化,於是,用樹的重心,這個DP很容易,但是,要每棵子樹都要求重心呢? 以某一棵子樹為研究對象,有多少個點對滿足 d[i] + d[j] <= k 呢? 對這個子樹 dfs求出 d ,距離 “根” 的距離(這個根是變化的); 將所有 d排序,掃描即可。 從根出發,遞歸到子節點,子節點再求,這樣子節點求得的會有一部分重合。減去經過父親結點的那些 <= k 的點對(此時,就是求以子節點為根,系數相差 d[f][v] 的 點對)。 至此,這個關於 點的 樹分治,就解決了!!! 男人八題寫了3題了。
#include <cstdio>
#include 
<cstring> #include <algorithm> #include <vector> using namespace std; #define N 10005 struct Node { int v,l; }; vector<Node> g[N]; int n,k; int s[N],f[N]; bool done[N]; int size; int root; void getroot(int u,int fa) { s[u] = 1; f[u] = 0; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(v!=fa&&!done[v]) { getroot(v,u); s[u] +=s[v]; f[u] = max(f[u],s[v]); } } f[u] = max(f[u],size-s[u]); if(f[u]<f[root]) root = u; } vector<int> dep; int d[N]; void getdep(int u,int fa) { dep.push_back(d[u]); s[u] = 1; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(v!=fa&&!done[v]) { d[v] = d[u] + g[u][i].l; getdep(v,u); s[u]+=s[v]; } } } int calc(int u,int init) { dep.clear(); d[u] = init; getdep(u,0); sort(dep.begin(),dep.end()); int ret = 0; for(int l=0,r=dep.size()-1;l<r;) if(dep[l]+dep[r]<=k) ret += r-l++; else r--; return ret; } int ans; void work(int u) { ans+=calc(u,0); done[u] = true; for(int i=0; i < (int)g[u].size(); i++) { int v = g[u][i].v; if(!done[v]) { ans-=calc(v,g[u][i].l); f[0] = size = s[v]; getroot(v,root=0); work(root); } } } int main() { while(scanf("%d%d",&n,&k),n) { for(int i=0; i <= n; i++) g[i].clear(); memset(done,0,sizeof(done)); int u,v,l; for(int i=1; i < n; i++) { scanf("%d%d%d",&u,&v,&l); g[u].push_back((Node){v,l}); g[v].push_back((Node){u,l}); } f[0] = size = n; getroot(1,root=0); ans = 0; work(root); printf("%d\n",ans); } return 0; }

POJ 1741 男人八題——樹分治