POJ1741(SummerTrainingDay08-G 树的点分治)
Tree
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 23380 | Accepted: 7748 |
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.
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.
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
1 //2017-08-09 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 #include <vector> 7 8 using namespace std; 9 10 const int N = 10010; 11 int n, k, MAX, root, cnt, answer; 12 13 //链式前向星 14 int head[N], tot; 15 struct Edge{ 16 int next, to, w; 17 }edge[N<<4]; 18 19 void add_edge(int u, int v, int w){ 20 edge[tot].w = w; 21 edge[tot].to = v; 22 edge[tot].next = head[u]; 23 head[u] = tot++; 24 } 25 26 int size[N];//size[i]表示以i为根的子树的大小,包括i。 27 int maxson[N];//maxson[i]表示以i为根的子树的最大儿子的大小。 28 int dis[N];//dis[i]表示i到根的距离。 29 bool vis[N];//vis[i]用来标记i点是否被删除。 30 31 void init(int n){ 32 answer = 0; 33 tot = 0; 34 memset(vis, 0, sizeof(vis)); 35 memset(head, -1, sizeof(head)); 36 } 37 38 //计算出子树的大小 39 void dfs_size(int u, int fa){ 40 size[u] = 1; 41 maxson[u] = 0; 42 for(int i = head[u]; ~i; i = edge[i].next){ 43 int v = edge[i].to; 44 if(vis[v] || v == fa)continue; 45 dfs_size(v, u); 46 size[u] += size[v]; 47 if(size[v] > maxson[u]) 48 maxson[u] = size[v]; 49 } 50 } 51 52 //找子树的重心。最大子树最小的点即为树的重心。 53 void dfs_root(int r, int u, int fa){ 54 if(size[r] - size[u] > maxson[u])//size[r]-size[u]为u上面的树的尺寸 55 maxson[u] = size[r] - size[u]; 56 if(maxson[u] < MAX){ 57 MAX = maxson[u]; 58 root = u; 59 } 60 for(int i = head[u]; ~i; i = edge[i].next){ 61 int v = edge[i].to; 62 if(vis[v] || v == fa)continue; 63 dfs_root(r, v, u); 64 } 65 } 66 67 //计算出子树中每个点距离重心的距离 68 void dfs_dis(int u, int d, int fa){ 69 dis[cnt++] = d; 70 for(int i = head[u]; ~i; i = edge[i].next){ 71 int v = edge[i].to; 72 if(vis[v] || v == fa)continue; 73 dfs_dis(v, d+edge[i].w, u); 74 } 75 } 76 77 //计算出以u为根的子树中距离和小于k的点对数 78 int cal(int u, int d){ 79 int ans = 0; 80 cnt = 0; 81 dfs_dis(u, d, 0); 82 sort(dis, dis+cnt); 83 for(int i = 0, j = cnt-1; i < j; i++){ 84 while(dis[i]+dis[j] > k && i < j)//双指针 85 j--; 86 ans += j-i; 87 } 88 return ans; 89 } 90 91 //分治,找到树的重心,分为经过重心的点对和不经过重心的点对。 92 void solve(int u){ 93 MAX = n; 94 dfs_size(u, 0); 95 dfs_root(u, u, 0); 96 answer += cal(root, 0); 97 vis[root] = 1; 98 for(int i = head[root]; ~i; i = edge[i].next){ 99 int v = edge[i].to; 100 if(vis[v])continue; 101 answer -= cal(v, edge[i].w); 102 solve(v); 103 } 104 } 105 106 int main() 107 { 108 //freopen("dataIn.txt", "r", stdin); 109 while(scanf("%d%d", &n, &k)!=EOF){ 110 if(!n && !k)break; 111 int u, v, w; 112 init(n); 113 for(int i = 0; i < n-1; i++){ 114 scanf("%d%d%d", &u, &v, &w); 115 add_edge(u, v, w); 116 add_edge(v, u, w); 117 } 118 solve(1); 119 printf("%d\n", answer); 120 } 121 122 return 0; 123 }