POJ1741--Tree (树的点分治) 求树上距离小于等于k的点对数
2015-03-23 13:46
309 查看
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
Sample Output
题意:求树上距离小于等于k的点对数。。
我是用 点的分治做的,,据说还可以用启发式合并做,,附上链接http://blog.csdn.net/asdfgh0308/article/details/39845489。。挖个坑。
定义树的重心 s 为 删除s点后的 最大子树的点数 小于n/2。 那么对于任意满足条件的点对 有两种情况,,
其路径 1要么经过s 2要么不经过s。。
对于1 我们只需要 求出 以s为根的子树的点到s的距离即可。。
对于2 可以递归处理 分解为 多个1。。然后就可以求出来了。。
复杂度为nlogn*logn
②第二种姿势,,200ms左右
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 12276 | Accepted: 3886 |
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
#include <set> #include <map> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef unsigned long long ull; typedef long long ll; const int inf = 0x3f3f3f3f; const double eps = 1e-8; const int maxn = 1e4+10; struct Edge { int to, len; Edge (int _x, int _len) { to = _x; len = _len; } }; vector<Edge>G[maxn << 1]; int siz[maxn]; bool vis[maxn]; void Get_size(int root, int father) { siz[root] = 1; for (int i = 0; i < G[root].size(); i++) { int v = G[root][i].to; if (v == father || vis[v] == true) continue; Get_size(v, root); siz[root] += siz[v]; } } typedef pair<int,int>pii; pii FindGravity(int root, int father, int t) { pii res = make_pair(inf, -1); int m = 0, sum = 1; for (int i = 0; i < G[root].size(); i++) { int v = G[root][i].to; if (v == father || vis[v] == true) continue; res = min(res, FindGravity(v, root, t)); m = max(m, siz[v]); sum += siz[v]; } m = max(m, t-sum); res = min(res, make_pair(m, root)); return res; } void Get_len(int root, int father, int d, vector<int>&len) { len.push_back(d); for (int i = 0; i < G[root].size(); i++) { int v = G[root][i].to; if (v == father || vis[v] == true) continue; Get_len(v, root, d+G[root][i].len, len); } } int K; int cnt_pair(vector<int>&ds) { int res = 0; sort (ds.begin(), ds.end()); int j = ds.size() - 1; for (int i = 0; i < ds.size(); i++) { while (j > i && ds[i] + ds[j] > K) { j--; } res += (j > i ? j - i : 0); } return res; } int solve(int root) { int ans = 0; Get_size(root, -1); int s = FindGravity(root, -1, siz[root]).second; if (s == -1) return 0; vis[s] = true; for (int i = 0; i < G[s].size(); i++) { int v = G[s][i].to; if (vis[v] == true) continue; ans += solve(v); } vector<int>ds; ds.push_back(0); for (int i = 0; i < G[s].size(); i++) { int v = G[s][i].to; if (vis[v] == true) continue; vector<int>rds; Get_len(v, s, G[s][i].len, rds); ans -= cnt_pair(rds); ds.insert(ds.end(), rds.begin(), rds.end()); } ans += cnt_pair(ds); vis[s] = false; return ans; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int n; while ( scanf ("%d%d", &n, &K), n && K) { int u, v, c; for (int i = 0; i <= n; i++) G[i].clear(); for (int i = 0; i < n-1; i++) { scanf ("%d%d%d", &u, &v, &c); G[u].push_back(Edge(v,c)); G[v].push_back(Edge(u,c)); } printf("%d\n", solve(n/2+1)); } return 0; }
②第二种姿势,,200ms左右
#include <set> #include <map> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef unsigned long long ull; typedef long long ll; const int inf = 0x3f3f3f3f; const double eps = 1e-8; const int maxn = 1e4+10; struct Edge { int to, len, next; }e[maxn << 1]; int head[maxn], tot, N, K; void add_edge(int u, int v, int c) { e[tot].to = v; e[tot].len = c; e[tot].next = head[u]; head[u] = tot++; } int siz[maxn],Mtree[maxn]; // Mtree为最大子树的大小 siz为子树的大小 bool vis[maxn]; int center; void FindGravity(int u, int father, int cnt) // 查找重心 center { siz[u] = 1; Mtree[u] = 0; for (int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if (v == father || vis[v] == true) continue; FindGravity(v, u, cnt); siz[u] += siz[v]; Mtree[u] = max(Mtree[u], siz[v]); } Mtree[u] = max(cnt - siz[u], Mtree[u]); if (Mtree[center] > Mtree[u]) center = u; } int S[maxn], dep[maxn], top; void Get_len(int u, int father, int d) { S[top++] = d; for (int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if (vis[v] == true || v == father) continue; // dep[v] = dep[u] + e[i].len; Get_len(v, u, d+e[i].len); } } int Get_cnt(int u, int d) { int res = 0; top = 0; //dep[u] = d; Get_len(u, 0, d); sort (S, S+top); int j = top - 1; for (int i = 0; i < top; i++) { while (j > i && S[i] + S[j] > K) j--; res += (j > i ? j-i : 0); } return res; } int ans; void solve(int r) { vis[r] = true; ans += Get_cnt(r, 0); for (int i = head[r]; ~i; i = e[i].next) { int v = e[i].to; if (vis[v] == true) continue; ans -= Get_cnt(v, e[i].len); center = 0; FindGravity(v, r, siz[v]); solve(center); } } void init() { tot = 0; Mtree[0] = N; memset(head, -1, sizeof(head)); memset(vis, false, sizeof(vis)); center = 0; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif while (scanf ("%d%d", &N,&K), N && K) { init(); int u, v, c; for (int i = 0; i < N-1; i++) { scanf ("%d%d%d", &u, &v, &c); add_edge(u, v, c); add_edge(v, u, c); } ans = 0; FindGravity(N/2+1, -1, N); solve(center); printf("%d\n", ans); } return 0; }
相关文章推荐
- Codeforces Round #358 (Div. 2) C. Alyona and the Tree(如果这棵树合法有一个条件:对于树上任意一个点,它的祖先到它的距离小于等于它自己的值)
- poj1741:Tree (树上点分治/treap+启发式合并)
- [poj1741 Tree]树上点分治
- poj1741 Tree (求树上任意两点之间权值和小于k的个数)(树分治)
- poj 1741(1987) 树分治(求距离小于某值的点对数)
- poj 1741 Tree 树上的分治+求树的重心
- 【POJ1741】Tree-树的点分治
- [POJ1741]Tree |点分治
- [Poj1741]Tree (点分治)
- 【poj1741】Tree 树的点分治
- 练习赛zi树上距离(分治)
- POJ1741 tree 【点分治】
- [POJ1741] Tree【树分治 点分治】
- poj1741 树上的分治
- [poj1741][tree] (树/点分治)
- poj 1741 Tree 树上的分治
- POJ 1741 Tree 树上分治
- POJ1741 tree 【点分治】
- POJ1741 Tree(树的点分治基础题)
- [POJ1741]Tree(点分治模板)