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。

 #include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e5+, M = 1e2+, mod = 1e9+, inf = 1e9+;
typedef long long ll; int n,m,root,t,ans,allnode,siz[N],K,head[N],vis[N],d[N];
int deep[N];//路径长度//deep[0]子节点个数
int f[N];//重心 struct edg{int to,next,v;}e[N * ];//前向星存边
void add(int u,int v,int w) {e[t].to=v;e[t].next=head[u];e[t].v=w;head[u]=t++;}//加边 //获取重心
void getroot(int x,int fa) {
siz[x] = ;
f[x] = ;
for(int i=head[x];i;i=e[i].next) {
int to = e[i].to;
if(to == fa || vis[to]) continue;
getroot(to,x);
siz[x] += siz[to];
f[x] = max(f[x] , siz[to]);
}
f[x] = max(allnode-siz[x] , f[x]);
if(f[x] < f[root]) root = x;
} void getdeep(int x,int fa) {//获取子树所有节点与根的距离
deep[++deep[]] = d[x];
for(int i=head[x];i;i=e[i].next) {
int to = e[i].to;
if(to == fa || vis[to]) continue;
d[to] = d[x] + e[i].v;
getdeep(to,x);
}
}
int cal(int x,int now) {//计算当前以重心x的子树下,所有情况的答案
d[x]=now;deep[]=;
getdeep(x,);
sort(deep+,deep+deep[]+);
int all = ;
for(int l=,r=deep[];l<r;) {
if(deep[l]+deep[r] <= K) {all += r-l;l++;}
else r--;
}
return all;
} void work(int x) {//以x为重心进行计算
vis[x] = ;
ans+=cal(x,);
for(int i=head[x];i;i=e[i].next) {
int to = e[i].to;
if(vis[to]) continue;
ans -= cal(to,e[i].v);
allnode = siz[to];
root=;
getroot(to,x);
work(root);
}
} int main()
{
while(~scanf("%d%d",&n,&K)) {
if(!n&&!m) break;
memset(head,,sizeof(head));
memset(vis,,sizeof(vis));
t = ;
for(int i=;i<n;i++) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c) , add(b,a,c);
}
root=ans=;
allnode=n;f[]=inf;
getroot(,);
work(root);
printf("%d\n",ans);
}
}

POJ 1741 Tree(树的点分治,入门题)的更多相关文章

  1. POJ 1741 Tree 树分治

    Tree     Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...

  2. poj 1741 Tree (树的分治)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 30928   Accepted: 10351 Descriptio ...

  3. POJ 1741 Tree 树的分治(点分治)

    题目大意:给出一颗无根树和每条边的权值,求出树上两个点之间距离<=k的点的对数. 思路:树的点分治.利用递归和求树的重心来解决这类问题.由于满足题意的点对一共仅仅有两种: 1.在以该节点的子树中 ...

  4. poj 1741(树的点分治)

    Tree Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dis ...

  5. POJ 1741/1987 树的点分治

    树的点分治,主要思想是每次找子树的重心,计算经过根节点的情况数,再减去点对属于同一子树的情况. #include <iostream> #include <vector> #i ...

  6. POJ 1741.Tree 树分治 树形dp 树上点对

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 24258   Accepted: 8062 Description ...

  7. POJ 1741 Tree 树的分治

    原题链接:http://poj.org/problem?id=1741 题意: 给你棵树,询问有多少点对,使得这条路径上的权值和小于K 题解: 就..大约就是树的分治 代码: #include< ...

  8. POJ 1741 Tree 树形DP(分治)

    链接:id=1741">http://poj.org/problem?id=1741 题意:给出一棵树,节点数为N(N<=10000),给出N-1条边的两点和权值,给出数值k,问 ...

  9. poj1741_Tree(树的点分治入门题)

    题目链接:poj1741_Tree 题意: 给你一颗n个节点的树,每条边有一个值,问有多少点对(u,v),满足u->v的最短路径小于k. 题解: 典型的树的分治,板子题. #include< ...

随机推荐

  1. 'boost/iterator/iterator_adaptor.hpp' file not found之xcode生成时报错的解决方案

    xcode生成rn(0.49.3)项目的时候出现“'boost/iterator/iterator_adaptor.hpp' file not found之xcode”报错. 原因: /Users/x ...

  2. 如何写一个SSH项目(一)程序设计大体思路

    SSH:分别是指Spring,Struts,Hibernate. 后来Struts2代替了Struts,所以我们常说的SSH是指Spring,Struts2,Hibenate. 其中Spring一般用 ...

  3. ActiveMQ (一) 初识ActiveMQ

    了解JMS JMS即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进 ...

  4. 阿里云Centos7 apache配置

    其实很简单,主要是有坑. 首先填坑,在阿里云安全策略上开放要访问的端口,然后配置firewall添加对应端口开放. firewall-cmd --zone=public --add-port=8011 ...

  5. NOI 2005维护数列

    题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...

  6. 关于 jar 包数据更新的问题

    参考: 人乐草心的博文 如果要更新一个 jar 包内文件的一些信息,又不想重新编译,发包,可以如下操作. Extract JAR file unzip 拆包方式 unzip xxx.jar [ -d ...

  7. MacOS 安装 Jenkins

    jenkins 官网安装教程:https://jenkins.io/doc/ 参考博文:http://blog.csdn.net/taishanduba/article/details/5045260 ...

  8. python的defaultdict

    defaultdict是dict的一个子类,接受一个工厂函数作为参数,当访问defaultdict中不存在的key时,会将工厂函数的返回值作为默认的value. class defaultdict(d ...

  9. Micro Templating源码分析

    关于模板,写页面的人们其实一直在用,asp.net , jsp , php, nodejs等等都有他的存在,当然那是服务端的模板. 前端模板,作为前端人员肯定是多少有接触的,Handlebars.js ...

  10. 在Ubuntu14.04上搭建自己的OpenVPN服务器并通过它上网

    背景 学校宿舍端口可以配置静态IP连校内网,也可以连到实验室的服务器:实验室的服务器可以连外网:但宿舍要连外网就要花钱买PPPoE账号了.作为壮哉我大计院的一员,本着发扬专(neng)业(sheng) ...