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 }