Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 20816   Accepted: 6820

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

【分析】

给一棵边带权树,问两点之间的距离小于等于K的点对有多少个。

将无根树转化成有根树进行观察。满足条件的点对有两种情况:两个点的路径横跨树根,两个点位于同一颗子树中。

如果我们已经知道了此时所有点到根的距离a[i],a[x] + a[y] <= k的(x, y)对数就是结果,这个可以通过排序之后O(n)的复杂度求出。然后根据分治的思想,分别对所有的儿子求一遍即可,但是这会出现重复的——当前情况下两个点位于一颗子树中,那么应该将其减掉(显然这两个点是满足题意的,为什么减掉呢?因为在对子树进行求解的时候,会重新计算)。

在进行分治时,为了避免树退化成一条链而导致时间复杂度变为O(N^2),每次都找树的重心,这样,所有的子树规模就会变的很小了。时间复杂度O(Nlog^2N)。

树的重心的算法可以线性求解。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define lson(x) ((x<<1))
#define rson(x) ((x<<1)+1)
using namespace std;
typedef long long ll;
const int N=1e5+;
const int M=1e6+;
int n,m,k,tot,size,root,ans;
int head[N],s[N],f[N],d[N];
bool done[N];
vector<int>dep;
struct man{
int to,next,l;
}edg[N*];
void add(int u,int v,int l){
edg[tot].to=v;edg[tot].l=l;edg[tot].next=head[u];head[u]=tot++;
}
void getroot(int u,int fa){
s[u]=;f[u]=;
for(int i=head[u];i!=-;i=edg[i].next){
int v=edg[i].to;
if(v!=fa&&!done[v]){
getroot(v,u);
s[u]+=s[v];
f[u]=max(f[u],s[v]);
}
}
f[u]=max(f[u],size-s[u]);
if(f[u]<f[root])root=u;
}
void getdep(int u,int fa){
dep.push_back(d[u]);
s[u]=;
for(int i=head[u];i!=-;i=edg[i].next){
int v=edg[i].to;
if(v!=fa&&!done[v]){
d[v]=d[u]+edg[i].l;
getdep(v,u);
s[u]+=s[v];
}
}
}
int calc(int u,int init){
dep.clear();
d[u]=init;
getdep(u,);
sort(dep.begin(),dep.end());
int ret=;
for(int l=,r=dep.size()-;l<r; ){
if(dep[l]+dep[r]<=k)ret+=r-l++;
else r--;
}
return ret;
}
void work(int u){
ans+=calc(u,);
done[u]=true;
for(int i=head[u];i!=-;i=edg[i].next){
int v=edg[i].to;
if(!done[v]){
ans-=calc(v,edg[i].l);
f[]=size=s[v];
getroot(v,root=);
work(root);
}
}
}
int main(){
while(~scanf("%d%d",&n,&k)&&n&&k){
tot=ans=;f[]=size=n;
met(head,-);met(done,false);
int u,v,l;
for(int i=;i<n;i++){
scanf("%d%d%d",&u,&v,&l);
add(u,v,l);add(v,u,l);
}
getroot(,root=);
work(root);
printf("%d\n",ans);
}
return ;
}

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

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

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

  2. POJ 1741 Tree 树分治

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

  3. [bzoj 1468][poj 1741]Tree [点分治]

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

  4. POJ 1741 Tree(点分治点对<=k)

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

  5. POJ 1741 Tree ——点分治

    [题目分析] 这貌似是做过第三道以Tree命名的题目了. 听说树分治的代码都很长,一直吓得不敢写,有生之年终于切掉这题. 点分治模板题目.自己YY了好久才写出来. 然后1A了,开心o(* ̄▽ ̄*)ブ ...

  6. [poj 1741]Tree 点分治

    题意 求树上距离不超过k的点对数,边权<=1000 题解     点分治.     点分治的思想就是取一个树的重心,这种路径只有两种情况,就是经过和不经过这个重心,如果不经过重心就把树剖开递归处 ...

  7. POJ - 1741 - Tree - 点分治 模板

    POJ-1741 题意: 对于带权的一棵树,求树中距离不超过k的点的对数. 思路: 点分治的裸题. 将这棵树分成很多小的树,分治求解. #include <algorithm> #incl ...

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

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

  9. POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量

    POJ 1741. Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 34141   Accepted: 11420 ...

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

                                                                                                 POJ 174 ...

随机推荐

  1. 【题解】HNOI2010合唱队

    我果然还是太弱了呜呜呜……洛谷P3205 区间dp:注意到一段区间最两侧的人必然是最后加入队伍的所以由此我们可以分成两种情况来讨论. 一种是最后一个加入的人是左边的,另一种是右边的.那么状态:dp[i ...

  2. 洛谷 P2611 [ZJOI2012]小蓝的好友 解题报告

    P2611 [ZJOI2012]小蓝的好友 题目描述 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事,为了回馈各位比赛选手,此题的主角是贯穿这次比赛的关键人物--小蓝的好友. 在帮小 ...

  3. gcc用法小记

    By francis_hao    Feb 13,2017 概要 这里只列出了最常用的选项   选项解释 -c|-S|-E 启动gcc编译器时,它会顺序执行预处理.编译.汇编和连接(四个阶段的详细介绍 ...

  4. HDU 3446 有贪心思想的01背包

    Proud Merchants Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) ...

  5. bzoj 2566 calc 拉格朗日插值

    calc Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 377  Solved: 226[Submit][Status][Discuss] Descr ...

  6. mysql————表类型(存储引擎)的选择

    表类型(存储引擎)的选择 7.1 mysql存储引擎概述 插件式存储引擎是mysql数据库最重要的特性之一,用户可以根据应用的需要选择ruhr存储和索引数据,是否使用事务等. InnoDB和BDB提供 ...

  7. Active Directory Domain Services in Windows Server 2016/2012

    Applies To: Windows Server 2016, Windows Server 2012 R2, Windows Server 2012 You will find links to ...

  8. 二进制转16进制JAVA代码

    public class Binary2Hex { public static void main(String[] args) { String bString ="10101000&qu ...

  9. vue+koa+mysql简易demo

    功能支持网址收藏编辑 代码: https://github.com/lanleilin/lanOdyssey/tree/master/vueKoa/webCollection1 运行方法: 在serv ...

  10. GDOI2015的某道题目

    分析: 考试的时候由于一些神奇的原因(我就不说是什么了)...没有想$C$题,直接交了个暴力上去... 然后发现暴力的数组开的太大,由于矩阵乘法的需要做$m$次初始化,所以只拿到了10分... 我们一 ...