首页 > 其他 > 详细

POJ1741--Tree (树的点分治) 求树上距离小于等于k的点对数

时间:2015-03-23 15:14:01      阅读:155      评论:0      收藏:0      [点我收藏+]
Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 12276   Accepted: 3886

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的点对数。。

我是用 点的分治做的,,据说还可以用启发式合并做,,附上链接http://blog.csdn.net/asdfgh0308/article/details/39845489。。挖个坑。

定义树的重心 s 为 删除s点后的 最大子树的点数 小于n/2。  那么对于任意满足条件的点对 有两种情况,,

其路径 1要么经过s  2要么不经过s。。

对于1 我们只需要 求出 以s为根的子树的点到s的距离即可。。

对于2  可以递归处理 分解为 多个1。。然后就可以求出来了。。

复杂度为nlogn*logn

  1 #include <set>
  2 #include <map>
  3 #include <cmath>
  4 #include <ctime>
  5 #include <queue>
  6 #include <stack>
  7 #include <cstdio>
  8 #include <string>
  9 #include <vector>
 10 #include <cstdlib>
 11 #include <cstring>
 12 #include <iostream>
 13 #include <algorithm>
 14 using namespace std;
 15 typedef unsigned long long ull;
 16 typedef long long ll;
 17 const int inf = 0x3f3f3f3f;
 18 const double eps = 1e-8;
 19 const int maxn = 1e4+10;
 20 struct Edge
 21 {
 22     int to, len;
 23     Edge (int _x, int _len)
 24     {
 25         to = _x;
 26         len = _len;
 27     }
 28 };
 29 vector<Edge>G[maxn << 1];
 30 int siz[maxn];
 31 bool vis[maxn];
 32 void Get_size(int root, int father)
 33 {
 34     siz[root] = 1;
 35     for (int i = 0; i < G[root].size(); i++)
 36     {
 37         int v = G[root][i].to;
 38         if (v == father || vis[v] == true)
 39             continue;
 40         Get_size(v, root);
 41         siz[root] += siz[v];
 42     }
 43 }
 44 typedef pair<int,int>pii;
 45 pii FindGravity(int root, int father, int t)
 46 {
 47     pii res = make_pair(inf, -1);
 48     int m = 0, sum = 1;
 49     for (int i = 0; i < G[root].size(); i++)
 50     {
 51         int v = G[root][i].to;
 52         if (v == father || vis[v] == true)
 53             continue;
 54         res = min(res, FindGravity(v, root, t));
 55         m = max(m, siz[v]);
 56         sum += siz[v];
 57     }
 58     m = max(m, t-sum);
 59     res = min(res, make_pair(m, root));
 60     return res;
 61 }
 62 void Get_len(int root, int father, int d, vector<int>&len)
 63 {
 64     len.push_back(d);
 65     for (int i = 0; i < G[root].size(); i++)
 66     {
 67         int v = G[root][i].to;
 68         if (v == father || vis[v] == true)
 69             continue;
 70         Get_len(v, root, d+G[root][i].len, len);
 71     }
 72 }
 73 int K;
 74 int cnt_pair(vector<int>&ds)
 75 {
 76     int res = 0;
 77     sort (ds.begin(), ds.end());
 78     int j = ds.size() - 1;
 79     for (int i = 0; i < ds.size(); i++)
 80     {
 81         while (j > i && ds[i] + ds[j] > K)
 82         {
 83             j--;
 84         }
 85         res += (j > i ? j - i : 0);
 86     }
 87     return res;
 88 }
 89 int solve(int root)
 90 {
 91     int ans = 0;
 92     Get_size(root, -1);
 93     int s = FindGravity(root, -1, siz[root]).second;
 94     if (s == -1)
 95         return 0;
 96     vis[s] = true;
 97     for (int i = 0; i < G[s].size(); i++)
 98     {
 99         int v = G[s][i].to;
100         if (vis[v] == true)
101             continue;
102         ans += solve(v);
103     }
104     vector<int>ds;
105     ds.push_back(0);
106     for (int i = 0; i < G[s].size(); i++)
107     {
108         int v = G[s][i].to;
109         if (vis[v] == true)
110             continue;
111         vector<int>rds;
112         Get_len(v, s, G[s][i].len, rds);
113         ans -= cnt_pair(rds);
114         ds.insert(ds.end(), rds.begin(), rds.end());
115     }
116     ans += cnt_pair(ds);
117     vis[s] = false;
118     return ans;
119 }
120 int main()
121 {
122     #ifndef ONLINE_JUDGE
123         freopen("in.txt","r",stdin);
124     #endif
125     int n;
126     while ( scanf ("%d%d", &n, &K), n && K)
127     {
128         int u, v, c;
129         for (int i = 0; i <= n; i++)
130             G[i].clear();
131         for (int i = 0; i < n-1; i++)
132         {
133             scanf ("%d%d%d", &u, &v, &c);
134             G[u].push_back(Edge(v,c));
135             G[v].push_back(Edge(u,c));
136         }
137         printf("%d\n", solve(n/2+1));
138     }
139     return 0;
140 }

 

POJ1741--Tree (树的点分治) 求树上距离小于等于k的点对数

原文:http://www.cnblogs.com/oneshot/p/4359622.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!