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. 【DVWA】【SQL Injection(Blind)】SQL盲注 Low Medium High Impossible

    1.初级篇 Low.php 加单引号提交 http://localhost/DVWA-master/vulnerabilities/sqli_blind/?id=1'&Submit=Submi ...

  2. CAD梦想看图6.0安卓版 20181022更新

    下载地址: http://www.mxdraw.com/ndetail_10109.html 1. 保存上次的文件浏览位置和绘制颜色 2. 调整工具条按钮位置和文字 3. 增加测量距离和面积时的捕捉功 ...

  3. 并发和多线程(七)--volatile

    volatile: 相当于轻量级的synchronized,只能用来修饰变量,线程安全的三个特性通过volatile能实现其中的两个 原子性: 在之前的文章有说到,通过Atomic相关类.synchr ...

  4. python 爬取微信好友列表和个性签名,绘制个性签名云图

    python爬取微信好友列表和个性签名,绘制个性签名云图 1. 简要介绍 本次实验主要用到下面几个库 : 1)itchat---用于微信接口,实现生成QR码,用于微信扫描登陆 2)re(正则化)--- ...

  5. python3的dict

    dict1 = {getlistUrl:getlistData,getskuUrl:getskuData, approveUrl:approveData, approvedlistUrl:approv ...

  6. 3.5.6 关系和boolean运算符

        Java包含丰富的关系运算符.要检测相等性,可以使用两个等号 == .例如, 3 == 7  的值为 false.       另外可以使用 != 检测不相等.例如,  3  ! = 7 的值 ...

  7. AD7606

    在只给芯片的RANGE和PAR_SER引脚上电(不给芯片加电)的时候,芯片严重发热. 改回给芯片加电,发热消失,芯片正常工作,芯片没有损坏. 版权声明:本文为博主原创文章,未经博主允许不得转载.

  8. IIS部署网站只有首页能访问,其他链接失效/运行.net+Access网站-可能原因:IIS未启用32位应用程序模式

    在64位的机子上IIS运行32位的.NET程序 由于64位操作系统不支持Microsoft OLE DB Provider for Jet驱动程 也不支持更早的Microsoft Access Dri ...

  9. Java基础学习总结(88)——线程创建与终止、互斥、通信、本地变量

    线程创建与终止 线程创建 Thread类与 Runnable 接口的关系 public interface Runnable {         public abstract void run(); ...

  10. objective-c 通告

    1. 通告和委托的区别 通告也能传递与事件相关的数据.通告不同于委托的地方在于,通告是在对象执行完成动作之后产生,而不是之前.受到通告的对象没有机会建议是否要执行动作,而且对象的通告可以有多个监听者( ...