http://poj.org/problem?

id=1741

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
/**
poj 1741 楼教主男人八题之中的一个:树分治
题目大意:给定一个带权树,问有多少对点之间的距离之和不超过k
解题思路:典型的树分治算法。 (转自ACMonster)
最easy想到的算法是:从每一个点出发遍历整棵树,统计数对个数。 由于时间复杂度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 <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=10015;
const int INF=0x3f3f3f3f;
int head[maxn],ip;
int siz[maxn],can[maxn],lst[maxn],d[maxn],fa[maxn];
int ans,tl,n,k,l1,l2; void init()
{
memset(head,-1,sizeof(head));
memset(can,0,sizeof(can));
ip=0;
ans=0;
} struct note
{
int v,w,next;
} edge[maxn*2]; void addedge(int u,int v,int w)
{
edge[ip].v=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++;
} void dfs1(int u,int pre)
{
siz[u]=1;
lst[++tl]=u;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if(v==pre||can[v])continue;
dfs1(v,u);
fa[v]=u;
siz[u]+=siz[v];
}
}
int getroot(int u,int pre)
{
tl=0;
dfs1(u,pre);
int pos,tmp=INF,d,y;
for(int i=1; i<=tl; i++)
{
d=0,y=lst[i];
for(int p=head[y]; p!=-1; p=edge[p].next)
{
int v=edge[p].v;
if(v==fa[y]||can[v])continue;
d=max(d,siz[v]);
}
if(y!=u)
d=max(d,siz[u]-siz[y]);
if(d<tmp)pos=y,tmp=d;
}
return pos;
} void dfs2(int u,int pre,int dis)
{
lst[++l1]=u;
d[u]=dis;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if(v==pre||can[v])continue;
dfs2(v,u,dis+edge[i].w);
}
} int getans(int *a,int l,int r)
{
int j=r,ret=0;
for(int i=l; i<=r; i++)
{
while(d[a[i]]+d[a[j]]>k&&j>i)j--;
ret+=j-i;
if(j==i)break;
}
return ret;
} inline bool cmp(int i,int j)
{
return d[i]<d[j];
}
void work(int u,int pre)
{
int root=getroot(u,pre);
l1=l2=0;
for(int i=head[root]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if(can[v]==0)
{
l2=l1;
dfs2(v,root,edge[i].w);
sort(lst+l2+1,lst+l1+1,cmp);
ans-=getans(lst,l2+1,l1);
}
}
lst[++l1]=root,d[root]=0;
sort(lst+1,lst+l1+1,cmp);
ans+=getans(lst,1,l1);
can[root]=1;
for(int i=head[root]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if(can[v]==0)
work(v,root);
}
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
if(n==0&&k==0)break;
init();
for(int i=0; i<n-1; i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);
}
work(1,0);
printf("%d\n",ans);
}
return 0;
}

poj 1741 楼教主男人八题之中的一个:树分治的更多相关文章

  1. nyoj137 取石子(三) 楼教主男人八题之一

    思路:一堆时,N态.两堆时,当两堆数量相同,P态,不同为N态.三堆时,先手可以变成两堆一样的,必胜N态. 此时可以总结规律:堆数为偶数可能且石子数都是两两相同的,为P态.分析四堆时,当四堆中两两数量一 ...

  2. poj 1737男人八题之一 orz ltc

    这是楼教主的男人八题之一.很高兴我能做八分之一的男人了. 题目大意:求有n个顶点的连通图有多少个. 解法: 1.  用总数减去不联通的图(网上说可以,我觉得时间悬) 2.    用动态规划(数学递推) ...

  3. Cogs 1714. [POJ1741][男人八题]树上的点对(点分治)

    [POJ1741][男人八题]树上的点对 ★★★ 输入文件:poj1741_tree.in 输出文件:poj1741_tree.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] ...

  4. POJ1742 Coins(男人八题之一)

    前言 大名鼎鼎的男人八题,终于见识了... 题面 http://poj.org/problem?id=1742 分析 § 1 多重背包 这很显然是一个完全背包问题,考虑转移方程: DP[i][j]表示 ...

  5. poj 1742(好题,楼天城男人八题,混合背包)

    Coins Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 33269   Accepted: 11295 Descripti ...

  6. poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 14874   Accepted: 5118 De ...

  7. 博弈论(男人八题):POJ 1740 A New Stone Game

    A New Stone Game Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 5694   Accepted: 3119 ...

  8. 新男人八题---AStringGame

    终于完成进度男人1/8,为了这题学了sam= = 题意先有一个串,n个子串,两个人轮流每次在子串上加字符,要求加完后还是原串的子串,最后不能加的就是输者,求赢的人 解法:sam之后在构造的状态图上跑s ...

  9. 【做题】cf603E——线段树分治

    首先感谢题解小哥,他在标算外又总结了三种做法. 此处仅提及最后一种做法. 首先考虑题目中要求的所有结点度数为奇数的限制. 对于每一个联通块,因为所有结点总度数是偶数,所以总结点数也必须是偶数的.即所有 ...

随机推荐

  1. github与git常用的一些基本配置与命令

    首次Git设置:ssh-keygen -t ras -C "email@xxx" 生成SSH (共钥)将生成的SSH key复制到文本框中即可(title默认为邮箱名) 你的身份( ...

  2. 北大ACM(POJ1016-Numbers That Count)

    Question:http://poj.org/problem?id=1016 问题点:水题. Memory: 232K Time: 125MS Language: C++ Result: Accep ...

  3. Spartan6系列之芯片配置模式详解

    1.   配置概述 Spartan6系列FPGA通过把应用程序数据导入芯片内部存储器完成芯片的配置.Spart-6 FPGA可以自己从外部非易失性存储器导入编程数据,或者通过外界的微处理器.DSP等对 ...

  4. java正则表达式匹配字符

    假设要匹配${2}中间为数字的这个类型的变量String,则 Pattern p = Pattern.compile("\\$\\{\\d+\\}"); Matcher m = p ...

  5. form表单中只有一个input时,按回车键后表单自动提交(form表单的一个小坑)

    form中只有一个input按回车键表单会自动提交 在一个form表单中,若只有一个input,按回车键表单会自动提交,但是当表单中存在多个input时,按回车键不会执行任何操作,这是form表单的一 ...

  6. react 中样式私有

    解决的问题,两个组件之间  有相同的class名,造成其中一个无法按预期的显示. import React, { Component } from 'react' import styles from ...

  7. 一个小demo熟悉Spring Boot 和 thymeleaf 的基本使用

    目录 介绍 零.项目素材 一. 创建 Spring Boot 项目 二.定制首页 1.修改 pom.xml 2.引入相应的本地 css.js 文件 3.编辑 login.html 4.处理对 logi ...

  8. xmpp 消息和好友上下线(3)

    原始地址:XMPPFrameWork IOS 开发(四) 消息 //收到消息 - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XM ...

  9. BZOJ 4976 [Lydsy1708月赛]宝石镶嵌

    [题解] 我们设总共有m个二进制位出现过1,那么如果n-k≥m,显然所有的1都可以出现,那么答案就是把所有的数或起来. 如果n-k<m,那么因为k不超过100,ai不超过1e5,所以n不超过11 ...

  10. mysql数据库变更监控(canal)

    背景: 1. 一些项目的基础功能会有Audit Trace, 以记录系统用户所做过的所有记录. 2. 实时备份数据,比如mysql主从复制,一个用于面向应用,一个用于对应用数据库的实时备份. 3. 实 ...