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. GeoServer CQL查询时中文问题

    1.GeoServer可以进行CQL与ECQL过滤,wms和wfs都可以 2.CQL与ECQL查询时,当传中文时会报错.将中文转为Unicode编码后就可以 /* *js Unicode编码转换 */ ...

  2. 使用node.js开发一个生成逐帧动画小工具

    在实际工作中我们已经下下来不下于一万个npm包了,像我们熟悉的 vue-cli,react-native-cli 等,只需要输入简单的命令 vue init webpack project,即可快速帮 ...

  3. 基于loghub的消息消费延迟监控

    我们可以把loghub当作一个消息中间件来使用.如果能知道当前的消费进度,自然好了,否则消费情况一无所知,总是有点慌! loghub消费分两种情况,一是普通消费,二是消费组消费: 消费组消费,logh ...

  4. 【2018寒假集训 Day2】【2019.5.11更新】【动态规划】花店橱窗布置(FLOWER)

    花店橱窗布置(FLOWER) 提交文件名:flower 问题描述: 某花店现有F束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,从左到右按1到V顺序编号, ...

  5. 【前端】 在前端利用数学函数知识+box-shadow解波浪图形

    序 今天正在刷数学函数相关题目,刷到了下面这篇文章,哇哦-有意思. 利用cos和sin实现复杂的曲线.传送门在下面. CSS 技巧一则 -- 在 CSS 中使用三角函数绘制曲线图形及展示动画 正巧在复 ...

  6. Java基础常见笔试题总结

    1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件 2.“sta ...

  7. 窗体的FormBorderStyle属性的不同效果

    查看原文:http://blog.xieyc.com/form-border-style/ 设置窗体边框可以通过设置窗体的FormBorderStyle属性设置.属性值可以通过枚举类型FormBord ...

  8. 【RN - 基础】之Image使用简介

    Image组件是用来加载图片的.React Native项目加载图片往往有三种方式: 从React Native项目中加载图片: 从APP项目中加载图片: 从网络中加载图片. Image组件加载图片 ...

  9. 利用modelarts和物体检测方式识别验证码

    近来有朋友让老山帮忙识别验证码.在github上查看了下,目前开源社区中主要流行以下几种验证码识别方式: tesseract-ocr模块: 这是HP实验室开发由Google 维护的开源 OCR引擎,内 ...

  10. luogu P2863 [USACO06JAN]牛的舞会The Cow Prom |Tarjan

    题目描述 The N (2 <= N <= 10,000) cows are so excited: it's prom night! They are dressed in their ...