题目大意:一棵带边权无根树,边权代表距离,求距离小于等于k的点对儿数。

题目分析:这两个点之间的路径只有两种可能,要么经过根节点,要么在一棵子树内。定义depth(i)表示点 i 到根节点的距离,belong(i)表示 i 所属的子树。如果路径经过根节点,那么满足depth(i)+depth(j)<=k并且belong(i)<>belong(j)的(i,j)为一个点对儿,如果在子树内,递归到子树即可。

总的过程就变成了这样的:

1、求出所有的depth;

2、求出满足depth(i)+depth(j)<=k并且belong(i)<>belong(j)的点对数;

3、递归到子树;

这道题的实现起来技巧性比较强:

1、在找点对儿(i,j)时,先将所有的depth排好序(快排的复杂度是O(NlogN)),然后就可以用O(N)的复杂度找出满足depth(i)+depth(j)<=k的点对儿数,不过这样找出的点对儿也包含belong(i)=belong(j)的,所以要减掉满足这一部分的点对儿数。

2、递归进行到每一棵子树时,都要以子树的重心为根节点开始进行上述的过程。这是因为要保证无论是什么样的树,都能以O(logN)的时间复杂度完成任务。

这样,总的时间复杂度为O(Nlog2N)。

# include<iostream>
# include<cstdio>
# include<cstring>
# include<vector>
# include<queue>
# include<list>
# include<set>
# include<map>
# include<string>
# include<cmath>
# include<cstdlib>
# include<algorithm>
using namespace std;
# define LL long long const int N=1005;
const int INF=1000000000; struct Edge
{
int to,w,nxt;
};
Edge e[N*20]; int n,m,cnt,mi;
int head[N*10];
int root,ans;
int ms[N*10];
int size[N*10];
int depth[N*10];
bool del[N*10]; void add(int u,int v,int w)
{
e[cnt].to=v;
e[cnt].w=w;
e[cnt].nxt=head[u];
head[u]=cnt++;
} void init()
{
ans=cnt=0;
int a,b,c;
memset(head,-1,sizeof(head));
memset(del,false,sizeof(del));
for(int i=1;i<n;++i){
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
} void getSize(int u,int fa)
{
size[u]=1;
ms[u]=0;
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
if(v==fa||del[v]) continue;
getSize(v,u);
size[u]+=size[v];
if(size[v]>ms[u]) ms[u]=size[v];
}
} void getRoot(int r,int u,int fa)
{
ms[u]=max(ms[u],size[r]-size[u]);
if(mi>ms[u]){
mi=ms[u];
root=u;
}
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
if(v==fa||del[v]) continue;
getRoot(r,v,u);
}
} void getDep(int u,int dep,int fa)
{
depth[cnt++]=dep;
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
if(v==fa||del[v]) continue;
getDep(v,dep+e[i].w,u);
}
} int cal(int u,int d)
{
cnt=0;
getDep(u,d,-1);
sort(depth,depth+cnt);
int l=0,r=cnt-1,res=0;
while(l<r){
while(l<r&&depth[l]+depth[r]>m) --r;
res+=r-l;
++l;
}
return res;
} void dfs(int u)
{
mi=n;
getSize(u,-1);
getRoot(u,u,-1);
ans+=cal(root,0);
del[root]=true;
for(int i=head[root];i!=-1;i=e[i].nxt){
int v=e[i].to;
if(del[v]) continue;
ans-=cal(v,e[i].w);
dfs(v);
}
} void solve()
{
dfs(1);
printf("%d\n",ans);
} int main()
{
while(~scanf("%d%d",&n,&m)&&(n+m))
{
init();
solve();
}
return 0;
}

  

POJ-1741 Tree (树上点分治)的更多相关文章

  1. POJ 1741 Tree 树上点分治

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

  2. poj 1741 Tree(点分治)

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

  3. POJ 1741 Tree (树分治入门)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 8554   Accepted: 2545 Description ...

  4. POJ 1741 Tree (点分治)

                                                                        Tree Time Limit: 1000MS   Memory ...

  5. POJ 1741 Tree 树的分治

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

  6. POJ 1741 Tree【树分治】

    第一次接触树分治,看了论文又照挑战上抄的代码,也就理解到这个层次了.. 以后做题中再慢慢体会学习. 题目链接: http://poj.org/problem?id=1741 题意: 给定树和树边的权重 ...

  7. poj 1741 Tree (树的分治)

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

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

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

  9. POJ 1741 Tree ——(树分治)

    思路参考于:http://blog.csdn.net/yang_7_46/article/details/9966455,不再赘述. 复杂度:找树的重心然后分治复杂度为logn,每次对距离数组dep排 ...

  10. POJ 1741 Tree 求树上路径小于k的点对个数)

                                                                                                 POJ 174 ...

随机推荐

  1. Fedora20的一些个人配置

    0,老传统 yum install screenfetch 1,关闭蜂鸣器 edit /etc/bashrc setterm -blength 0#setterm -bfreq 10 #这个可以设置声 ...

  2. 记录一些容易忘记的属性 -- UIView

    一个视图原来添加在某个父视图上,然后再将它添加到另外的一个视图上,这个视图会从原来的某个父视图中移除,添加到新的视图上. 子视图对象指针存在父视图的subviews数组中,说明,一个视图可以有多个子视 ...

  3. 2016 - 1- 22 NSURLConnetction --- GET请求

    ---恢复内容开始--- 一: 给服务器发送一个简单的GET请求 1.同步 // 发送一个GET请求给服务器 // 0.请求路径 NSURL *url = [NSURL URLWithString:@ ...

  4. UIkit框架之Uivew

    1.继承链:UIresponder:NSObject 2.通过使用 addGestureRecognizer:方法可以为视图添加手势 3.下面的属性都可以用来用于动画 @property frame ...

  5. zf2-tutorial调通,坑爹的init_autoloader.php

    zf2-tutorial的作者把init_autoloader.php内容写错了,新建个工程,把其中的这个文件的内容替一下,然后建库/建表,把local.ini打开(不是必须的),用户名/口令等配好, ...

  6. HDU 5820 (可持久化线段树)

    Problem Lights (HDU 5820) 题目大意 在一个大小为50000*50000的矩形中,有n个路灯.(n<=500000) 询问是否每一对路灯之间存在一条道路,使得长度为|x1 ...

  7. html input

    disabled="disabled" <input name="" type="checkbox" value="&quo ...

  8. Bootstrap组件On和Off语法

    $(document).on('click.bs.carousel.data-api','td',function(e){}) $(document).off('.carousel.data-api' ...

  9. strlen和mb_strlen的区别

    在php中常见的计算字符串长度的函数有:strlen和mb_strlen.当字符全是英文字符的时候,两者是一样.这里主要比较一下,中英文混排的时候,两个计算结果. 在PHP中,strlen与mb_st ...

  10. iOS开发环境C语言基础

    1 在“桌面”上创建一个文件夹Test 1.1 问题 在桌面上创建一个文件夹,我们需要了解Max OS X操作系统的操作方法.对于Max OS X操作系统,有两种方法可以在桌面上创建文件夹,一种方法是 ...