poj 1741 bzoj1468 Tree
2016-02-28 14:55
435 查看
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
Source
LouTiancheng@POJ
题目大意:求树上距离小于等于K的点对有多少个。
一道点分治题。
一个重要的问题是,为了防止退化,所以每次都要找到树的重心然后分治下去,所谓重心,就是删掉此结点后,剩下的结点最多的树结点个数最小。
每次分治,我们首先算出重心,为了计算重心,需要进行两次dfs,第一次把以每个结点为根的子树大小求出来,第二次是从这些结点中找重心
找到重心后,需要统计所有结点到重心的距离,看其中有多少对小于等于K,这里采用的方法就是把所有的距离存在一个数组里,进行快速排序,这是nlogn的,然后用一个经典的相向搜索O(n)时间内解决。但是这些求出来满足小于等于K的里面只有那些路径经过重心的点对才是有效的,也就是说在同一颗子树上的肯定不算数的,所以对每颗子树,把子树内部的满足条件的点对减去。
最后的复杂度是n(logn^2) 其中每次快排是nlogn 而递归的深度为logn
代码:
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
Source
LouTiancheng@POJ
题目大意:求树上距离小于等于K的点对有多少个。
一道点分治题。
一个重要的问题是,为了防止退化,所以每次都要找到树的重心然后分治下去,所谓重心,就是删掉此结点后,剩下的结点最多的树结点个数最小。
每次分治,我们首先算出重心,为了计算重心,需要进行两次dfs,第一次把以每个结点为根的子树大小求出来,第二次是从这些结点中找重心
找到重心后,需要统计所有结点到重心的距离,看其中有多少对小于等于K,这里采用的方法就是把所有的距离存在一个数组里,进行快速排序,这是nlogn的,然后用一个经典的相向搜索O(n)时间内解决。但是这些求出来满足小于等于K的里面只有那些路径经过重心的点对才是有效的,也就是说在同一颗子树上的肯定不算数的,所以对每颗子树,把子树内部的满足条件的点对减去。
最后的复杂度是n(logn^2) 其中每次快排是nlogn 而递归的深度为logn
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #define INF 0x7f7f7f7f using namespace std; int n,K,cnt,sum,ans,root; int head[10005],deep[10005],d[10005],f[10005],son[10005]; bool vis[10005]; struct data{int to,next,v;}e[20005]; inline int ReadInt() { int f = 1,x = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } void ins(int u, int v, int w) { e[++ cnt].to = v; e[cnt].next = head[u]; head[u] = cnt; e[cnt].v = w; } void insert(int u, int v, int w) { ins(u,v,w); ins(v,u,w); } void getroot(int x, int fa) { son[x] = 1; f[x] = 0; for(int i = head[x]; i; i = e[i].next) { if(e[i].to == fa || vis[e[i].to]) continue; getroot(e[i].to, x); son[x] += son[e[i].to]; f[x] = max(f[x], son[e[i].to]); } f[x] = max(f[x],sum - son[x]); if(f[x] < f[root]) root = x; } void getdeep(int x, int fa) { deep[++ deep[0]] = d[x]; for(int i = head[x]; i; i = e[i].next) { if(e[i].to == fa || vis[e[i].to]) continue; d[e[i].to] = d[x] + e[i].v; getdeep(e[i].to, x); } } int cal(int x, int y) { d[x] = y; deep[0] = 0; getdeep(x,0); sort(deep + 1, deep + deep[0] + 1); int t = 0, l, r; for(l = 1, r = deep[0]; l < r; ) { if(deep[l] + deep[r] <= K) { t += r - l; l ++;} else r --; } return t; } void Doit(int x) { ans += cal(x, 0); vis[x] = 1; for(int i = head[x]; i; i = e[i].next) { if(vis[e[i].to]) continue; ans -= cal(e[i].to, e[i].v); sum = son[e[i].to]; root = 0; getroot(e[i].to, root); Doit(root); } } int main() { while(1) { ans = 0; root = 0; cnt = 0; memset(head, 0, sizeof(head)); memset(vis, 0, sizeof(vis)); n = ReadInt(); K = ReadInt(); if(n == 0 && K == 0) break; for(int i = 1; i < n; i ++) { int u,v,w; u = ReadInt(); v = ReadInt(); w = ReadInt(); insert(u,v,w); } sum = n; f[0] = INF; getroot(1, 0); Doit(root); printf("%d\n",ans); } return 0; }
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- 用单调栈解决最大连续矩形面积问题
- 2632 Crashing Robots的解决方法
- 1573 Robot Motion (简单题)
- POJ 1200 Crazy Search(简单哈希)
- 【高手回避】poj3268,一道很水的dijkstra算法题