POJ-1741 Tree 【点分治】

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





思路:
点分治的经典题,看着黄学长的代码打出来的,很弱啊......
这题是求路径小于k的路径个数,如果暴力枚举对于1e5个结点肯定是要超时的。
这题能用点分治的原因是:对于某个点,所有的路径的要么经过它,要么不经过,因此我们只用处理经过当前节点的路径,因此可以基于点来分治。
点分治算法大致是:
1.无根树转化为有根树
  找到树的重心(重心即以该点为根其子树中拥有最大结点数的那颗的子树是最小的)作为根结点,保证了树的层数最小。

2.递归处理根的子树

Code:
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstring>
 6 using namespace std;
 7 #define INF 0x3f3f3f3f
 8 #define M(a, b) memset(a, b, sizeof(a))
 9 const int maxn = 1e5 + 5;
10 int n, k, root, sum, ans, d[maxn], deep[maxn], son[maxn], f[maxn];
11 bool vis[maxn];
12 struct node {
13     int to, w;
14 };
15 vector<node> G[maxn*2];
16 
17 void getroot(int x, int fa) {
18     son[x] = 1; f[x] = 0;
19     for (int i = 0; i < G[x].size(); ++i) {
20         int v = G[x][i].to;
21         if (v == fa || vis[v]) continue;
22         getroot(v, x);
23         son[x] += son[v];
24         f[x] = max(f[x], son[v]);
25     }
26     f[x] = max(f[x], sum-son[x]);
27     if (f[x] < f[root]) root = x;
28 }
29 
30 void getdeep(int x, int fa) {
31     deep[++deep[0]] = d[x];
32     for (int i = 0; i < G[x].size(); ++i) {
33         int v = G[x][i].to;
34         if (v == fa || vis[v]) continue;
35         d[v] = d[x] + G[x][i].w;
36         getdeep(v, x);
37     }
38 }
39 
40 int cal(int x, int now) {
41     int temp = 0, l, r;
42     d[x] = now, deep[0] = 0;
43     getdeep(x, 0);
44     sort(deep+1, deep+1+deep[0]);
45     l = 1, r = deep[0];
46     while (l < r) {
47         if (deep[l]+deep[r] <= k) {temp += r-l; l++;}
48         else r--;
49     }
50     return temp;
51 }
52 
53 void work(int x) {
54     ans += cal(x, 0);
55     vis[x] = 1;
56     for (int i = 0; i < G[x].size(); ++i) {
57         int v = G[x][i].to;
58         if (vis[v]) continue;
59         ans -= cal(v, G[x][i].w);
60         sum = son[v];
61         root = 0;
62         getroot(v, 0);
63         work(root);
64     }
65 }
66 
67 int main() {
68     ios::sync_with_stdio(false);
69     while(cin >> n >> k, n || k) {
70         memset(vis, 0, sizeof(vis));
71         int a, b, c;
72         for (int i = 1; i < n; ++i) {
73             cin >> a >> b >> c;
74             G[a].push_back(node{b, c});
75             G[b].push_back(node{a, c});
76         }
77         root = 0; ans = 0; 
78         sum = n; f[0] = INF;
79         getroot(1, 0);
80         work(root);
81         cout << ans << endl;
82         for (int i = 0; i <= n; ++i) G[i].clear();
83     } 
84 
85     return 0;
86 }
原文地址:https://www.cnblogs.com/robin1998/p/6536598.html