POJ 1741 Tree(树的点分治,入门题)
Tree
Time Limit: 1000MS |
Memory Limit: 30000K |
|
---|---|---|
Total Submissions: 21357 |
Accepted: 7006 |
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
Source
题目链接:http://poj.org/problem?id=1741
题目大意: 给定一棵N个节点、边上带权的树,再给出一个K,询问有多少个数对(i,j)满足i<j,且i与j两点在树上的距离小于等于K。 数据规模: 多组测试数据,每组数据满足N≤10000,1≤边上权值≤1000,1≤K≤10^9。 出处: 楼天城男人必做8题之一…… 思路: 最容易想到的算法是:从每个点出发遍历整棵树,统计数对个数。 由于时间复杂度O(N^2),明显是无法满足要求的。 对于一棵有根树, 树中满足要求的一个数对所对应的一条路径,必然是以下两种情况之一: 1、经过根节点 2、不经过根节点,也就是说在根节点的一棵子树中 对于情况2,可以递归求解,下面主要来考虑情况1。 设点i的深度为Depth[i],父亲为Parent[i]。 若i为根,则Belong[i]=-1,若Parent[i]为根,则Belong[i]=i,否则Belong[i]=Belong[Parent[i]]。 这三个量都可以通过一次BFS求得。 我们的目标是要统计:有多少对(i,j)满足i<j,Depth[i]+Depth[j]<=K且Belong[i]<>Belong[j] 如果这样考虑问题会变得比较麻烦,我们可以考虑换一种角度: 设X为满足i<j且Depth[i]+Depth[j]<=K的数对(i,j)的个数 设Y为满足i<j,Depth[i]+Depth[j]<=K且Belong[i]=Belong[j]数对(i,j)的个数 那么我们要统计的量便等于X-Y 求X、Y的过程均可以转化为以下问题: 已知A[1],A[2],...A[m],求满足i<j且A[i]+A[j]<=K的数对(i,j)的个数 对于这个问题,我们先将A从小到大排序。 设B[i]表示满足A[i]+A[p]<=K的最大的p(若不存在则为0)。我们的任务便转化为求出A所对应的B数组。那么,若B[i]>i,那么i对答案的贡献为B[i]-i。 显然,随着i的增大,B[i]的值是不会增大的。利用这个性质,我们可以在线性的时间内求出B数组,从而得到答案。 综上,设递归最大层数为L,因为每一层的时间复杂度均为“瓶颈”——排序的时间复杂度O(NlogN),所以总的时间复杂度为O(L*NlogN) 然而,如果遇到极端情况——这棵树是一根链,那么随意分割势必会导致层数达到O(N)级别,对于N=10000的数据是无法承受的。因此,我们在每一棵子树中选择“最优”的点分割。所谓“最优”,是指删除这个点后最大的子树尽量小。这个点可以通过树形DP在O(N)时间内求出,不会增加时间复杂度。这样一来,即使是遇到一根链的情况时,L的值也仅仅是O(logN)的。 因此,改进后算法时间复杂度为O(Nlog^2N),可以AC。
1 #include <iostream>
2 #include <cstdio>
3 #include <cmath>
4 #include <cstring>
5 #include <vector>
6 #include <algorithm>
7 using namespace std;
8 const int N = 1e5+20, M = 1e2+10, mod = 1e9+7, inf = 1e9+1000;
9 typedef long long ll;
10
11 int n,m,root,t,ans,allnode,siz[N],K,head[N],vis[N],d[N];
12 int deep[N];//路径长度//deep[0]子节点个数
13 int f[N];//重心
14
15 struct edg{int to,next,v;}e[N * 4];//前向星存边
16 void add(int u,int v,int w) {e[t].to=v;e[t].next=head[u];e[t].v=w;head[u]=t++;}//加边
17
18 //获取重心
19 void getroot(int x,int fa) {
20 siz[x] = 1;
21 f[x] = 0;
22 for(int i=head[x];i;i=e[i].next) {
23 int to = e[i].to;
24 if(to == fa || vis[to]) continue;
25 getroot(to,x);
26 siz[x] += siz[to];
27 f[x] = max(f[x] , siz[to]);
28 }
29 f[x] = max(allnode-siz[x] , f[x]);
30 if(f[x] < f[root]) root = x;
31 }
32
33 void getdeep(int x,int fa) {//获取子树所有节点与根的距离
34 deep[++deep[0]] = d[x];
35 for(int i=head[x];i;i=e[i].next) {
36 int to = e[i].to;
37 if(to == fa || vis[to]) continue;
38 d[to] = d[x] + e[i].v;
39 getdeep(to,x);
40 }
41 }
42 int cal(int x,int now) {//计算当前以重心x的子树下,所有情况的答案
43 d[x]=now;deep[0]=0;
44 getdeep(x,0);
45 sort(deep+1,deep+deep[0]+1);
46 int all = 0;
47 for(int l=1,r=deep[0];l<r;) {
48 if(deep[l]+deep[r] <= K) {all += r-l;l++;}
49 else r--;
50 }
51 return all;
52 }
53
54 void work(int x) {//以x为重心进行计算
55 vis[x] = 1;
56 ans+=cal(x,0);
57 for(int i=head[x];i;i=e[i].next) {
58 int to = e[i].to;
59 if(vis[to]) continue;
60 ans -= cal(to,e[i].v);
61 allnode = siz[to];
62 root=0;
63 getroot(to,x);
64 work(root);
65 }
66 }
67
68 int main()
69 {
70 while(~scanf("%d%d",&n,&K)) {
71 if(!n&&!m) break;
72 memset(head,0,sizeof(head));
73 memset(vis,0,sizeof(vis));
74 t = 1;
75 for(int i=1;i<n;i++) {
76 int a,b,c;
77 scanf("%d%d%d",&a,&b,&c);
78 add(a,b,c) , add(b,a,c);
79 }
80 root=ans=0;
81 allnode=n;f[0]=inf;
82 getroot(1,0);
83 work(root);
84 printf("%dn",ans);
85 }
86 }
- WP8微信5.3开始内测 支持Cortana语音 两微破冰了?
- 数据库进程间通信解决方案之MQ
- Extjs4.2 rest 与webapi数据交互----顺便请教了程序员的路该怎么走
- 这或许是对小白最友好的python入门了吧——7,组织列表
- 这或许是对小白最友好的python入门了吧——6,删除列表元素
- 集群开源软件赏:JGroups
- 看到他我一下子就悟了---委托
- 这或许是对小白最友好的python入门了吧——5,修改和添加列表元素
- 这或许是对小白最友好的python入门了吧——4,列表
- 【深度学习】自动驾驶:使用深度学习预测汽车的转向角度
- 这或许是对小白最友好的python入门了吧——3,数字处理
- 数据库恢复方案
- 这或许是对小白最友好的python入门了吧——2,变量和字符串
- Extjs4.2+webAPI+EF实现分页以及webapi的数据传值(续)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [打造自己的监控系统之执行Oracle命令]检查未绑定变量的语句(硬解析状况)
- httpclient使用HTTP代理实践
- 使用Python利用微信企业号发送报警信息
- C# Task.Delay() 和 Thread.Sleep() 区别
- Csharp实例:武汉智能安检闸机数据接收和解析
- [周末往期回顾]Oracle基本参数(LOG_ARCHIVE_DEST_n)
- [周末往期回顾]Oracle基本参数(SGA_TARGET)
- C#如何释放已经加载的图片
- 笔记本内置摄像头视频播放和存储
- [Data Guard全解析]5.Data Guard及ADG日常运维操作
- [Oracle 数据库日常操作] 表空间的日常运维命令
- Java 反射 -超详细讲解(附源码)
- [Data Guard全解析]6.物理备库的Switchover
- com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException异常解决方法
- [Oracle数据库日常操作] Redo Log的相关操作