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

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

题目大意:

给定一棵n元树,求有多少点对使得这两点的距离小于等于k。

树分治经典题。

以下删改自sdj222555的CSDN博客。

需要分治。可以看09年漆子超的论文。本题用到的是关于点的分治。

一个重要的问题是,为了防止退化,所以每次都要找到树的重心然后分治下去,所谓重心,就是删掉此结点后,剩下的结点最多的树结点个数最小。

每次分治,我们首先算出重心,为了计算重心,需要进行两次dfs,第一次把以每个结点为根的子树大小求出来,第二次是从这些结点中找重心。

当然在一次dfs过程中也能做到。另外虽然说不记忆化也能做到,但还是用个son数组记忆下吧。

另外,无向图的dfs不需要像我之前一样遇一个点打个vis标记,dfs定义成dfs(u,pa),保存该点的父亲就不会返回去啦。

找到重心后,需要统计所有结点到重心的距离,看其中有多少对小于等于K。

这里采用的方法就是把所有的距离存在一个数组里(不要忘了重心到自己的),进行快速排序,这是nlogn的,然后用一个经典的相向搜索O(n)时间内解决。

但是这些求出来满足小于等于K的里面只有那些路径经过重心的点对才是有效的,也就是说在同一颗子树上的肯定不算数的。所以对每颗子树,把子树内部的满足条件的点对减去。

最后的复杂度是n logn logn    其中每次快排是nlogn 而递归的深度为logn。

代码实现比较复杂,今后有时间还是可以再敲一次。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
typedef long long ll;
const int maxn=;
const int inf=; int n,k; int to[maxn*+];
int w[maxn*+];
int next[maxn*+];
int head[maxn+];
int cnt; void addedge(int a,int b,int c)
{
to[cnt]=b;w[cnt]=c;
next[cnt]=head[a];head[a]=cnt++;
} int ans;
int mins,root;
int son[maxn+];
int vis[maxn+];
int depth[maxn+];
int dis[maxn+],tot; void getroot(int u,int pa,int num)//求重心
{
int maxs=;
son[u]=;
for(int i=head[u];i!=-;i=next[i])
{
int l=to[i];
if(l!=pa&&!vis[l])
{
getroot(l,u,num);
maxs=std::max(maxs,son[l]);
son[u]+=son[l];
}
}
maxs=std::max(maxs,num-son[u]);
if(maxs<mins)
{
mins=maxs;
root=u;
}
} void getdepth(int u,int pa)//通过深度得出需要的dis值
{
for(int i=head[u];i!=-;i=next[i])
{
int l=to[i];
if(l!=pa&&!vis[l])
{
depth[l]=depth[u]+w[i];
dis[tot++]=depth[l];
getdepth(l,u);
}
}
} int calc(int u,int pa,int d)
{
depth[u]=;
tot=;
dis[tot++]=;
getdepth(u,pa);
int ret=;
std::sort(dis,dis+tot);
int i=,j=tot-;
while(i<j)//经典的相向搜索
{
while(dis[i]+dis[j]+d*>k&&i<j)
j--;
ret+=j-i;
i++;
}
return ret;
} void dfs(int x,int num)
{
mins=inf;
getroot(x,-,num);//找重心
ans+=calc(root,-,);//计算整棵树符合条件的对数
for(int i=head[root];i!=-;i=next[i])
{
int l=to[i];
if(!vis[l])
ans-=calc(l,root,w[i]);//减去每棵子树符合条件的对数
}
vis[root]=;//打标记
for(int i=head[root];i!=-;i=next[i])
{
int l=to[i];
if(!vis[l])
dfs(l,son[l]);//向子树递归
}
} int main()
{
while(scanf("%d%d",&n,&k),n||k)
{
memset(head,-,sizeof(head));
cnt=;
for(int i=,a,b,c;i<=n-;i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
} memset(vis,,sizeof(vis));
ans=;
dfs(,n); printf("%d\n",ans);
}
return ;
}

poj 1741 Tree (树的分治)的更多相关文章

  1. POJ 1741 Tree 树的分治

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

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

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

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

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

  4. POJ 1741 Tree(树的点分治,入门题)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description ...

  5. POJ 1741 Tree 树分治

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

  6. POJ 1741 Tree 树上点分治

    题目链接:http://poj.org/problem?id=1741 题意: 给定一棵包含$n$个点的带边权树,求距离小于等于K的点对数量 题解: 显然,枚举所有点的子树可以获得答案,但是朴素发$O ...

  7. POJ 1741 Tree (点分治)

                                                                        Tree Time Limit: 1000MS   Memory ...

  8. poj 1741 Tree(点分治)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 15548   Accepted: 5054 Description ...

  9. poj 1741 Tree(树的点分治)

    poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出 ...

随机推荐

  1. spring security进阶 使用数据库中的账户和密码认证

    目录 spring security 使用数据库中的账户和密码认证 一.原理分析 二.代码实现 1.新建一个javaWeb工程 2.用户认证的实现 3.测试 三.总结 spring security ...

  2. JSON——IT技术人员都必须要了解的一种数据交换格式

    JSON作为目前Web主流的数据交换格式,是每个IT技术人员都必须要了解的一种数据交换格式.尤其是在Ajax和REST技术的大行其道的当今,JSON无疑成为了数据交换格式的首选! 今天大家就和猪哥一起 ...

  3. Alibaba Nacos 学习(五):K8S Nacos搭建,使用nfs

    Alibaba Nacos 学习(一):Nacos介绍与安装 Alibaba Nacos 学习(二):Spring Cloud Nacos Config Alibaba Nacos 学习(三):Spr ...

  4. 【Stream—7】NetworkStream相关知识分享

    一.NetworkStream的作用 和先前的流有所不同,NetworkStream的特殊性可以在它的命名空间中得以了解(System.Net.Sockets),聪明的你马上就会反应过来:既然是在网络 ...

  5. 2019-10-23:渗透测试,基础学习,DVWA,Medium和Hight级别sql注入

    VWA的Medium和Hight级别sql注入 一,Medium级 服务端代码 <?php if( isset( $_POST[ 'Submit' ] ) ) {      // Get inp ...

  6. 图解AQS的设计与实现,手摸手带你实现一把互斥锁!

    AQS是并发编程中非常重要的概念,它是juc包下的许多并发工具类,如CountdownLatch,CyclicBarrier,Semaphore 和锁, 如ReentrantLock, ReaderW ...

  7. day20191006假期作业收尾

    国庆作业:(轻重缓急,重点代码看懂理解了.每天重心就是代码,理解代码,理解,understand the code.花时间花功夫.只要功夫深,铁杵磨成针.) 一.使用DAO设计模式操作数据库CRUD( ...

  8. 配置Tomcat监听80端口、配置Tomcat虚拟主机、Tomcat日志

    6月27日任务 16.4 配置Tomcat监听80端口16.5/16.6/16.7 配置Tomcat虚拟主机16.8 Tomcat日志扩展邱李的tomcat文档 https://www.linuser ...

  9. ios图片适配问题

    在不同的系统中显示不同的图片 代码优化 抽取一个分类

  10. 本地Docker Jenkins构建dotnet core web应用到Linux服务器 Docker上

    1.准备工作 环境 本地: Windows.Docker 代码仓库:Git 服务器:Linux.Docker 前提准备 创建个有dockerfile文件的dotnet core 3 web项目 新建一 ...