Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 25286   Accepted: 8421

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

点分治

点分治通常用以解决树上的分治问题,以点为界分治。【我做题还不够多,先不详细讲,之后再总结
这道题要求所有d(u,v) <= k的对数,直接枚举肯定不行,我们先求出路径经过树上一点的路径数

如何求通过一点的路径数?
我们以该点为根并求出树中所有点到根的距离,再全部排序,用双指针的方法O(n)统计d[u] + d[v] <= k的对数ans1
但是会将都在同一个子树,也就是不经过根的路径也算上,再对每一个子树算一遍ans2减去就好了
就是ans1 - ∑ans2

之后再向下分治,向每颗子树递归。

为防止极端数据,我们每次求出重心为根
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 10005,maxm = 40005,INF = 1000000000;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
return out * flag;
}
int N,K,vis[maxn],head[maxn],d[maxn],dep[maxn],nedge = 0,F[maxn],Siz[maxn],rt = 0,n,ans;
struct EDGE{int to,w,next;}edge[maxm];
inline void build(int u,int v,int w){
edge[nedge] = (EDGE){v,w,head[u]}; head[u] = nedge++;
edge[nedge] = (EDGE){u,w,head[v]}; head[v] = nedge++;
}
void getRT(int u,int fa){
int to; F[u] = 0; Siz[u] = 1;
Redge(u) if ((to = edge[k].to) != fa && !vis[to]){
getRT(to,u);
Siz[u] += Siz[to];
F[u] = max(F[u],Siz[to]);
}
F[u] = max(F[u],n - Siz[u]);
if (F[u] < F[rt]) rt = u;
}
void getdep(int u,int fa){
dep[++dep[0]] = d[u]; int to;
Redge(u) if (!vis[to = edge[k].to] && to != fa){
d[to] = d[u] + edge[k].w;
getdep(to,u);
}
}
int cal(int u,int D){
d[u] = D; dep[0] = 0;
getdep(u,0);
sort(dep + 1,dep + 1 + dep[0]);
int l = 1,r = dep[0],t = 0;
while (l < r)
if (dep[l] + dep[r] <= K) t += r - l++;
else r--;
return t;
}
void solve(int u){
ans += cal(u,0);
vis[u] = true; int to;
Redge(u) if (!vis[to = edge[k].to]){
ans -= cal(to,edge[k].w);
n = Siz[to]; rt = 0;
getRT(to,rt);
solve(rt);
}
}
int main(){
while (true){
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
int a,b,w; N = RD(); K = RD(); ans = 0; rt = 0; nedge = 0;
if (!N) break;
REP(i,N - 1){
a = RD(); b = RD(); w = RD();
build(a,b,w);
}
n = N; F[0] = INF;
getRT(1,0);
solve(rt);
printf("%d\n",ans);
}
return 0;
}

最新文章

  1. 《C#并发编程经典实例》笔记
  2. opencv+vs2010
  3. visual Sdudio 快捷键
  4. .net 后台读取pdf的值
  5. SQL Developer 4.0 启动报错“unable to create an instance of the java virtual machine located at path”
  6. Jquery基本、层次选择器
  7. (四)C语言柔性数组、指针赋值
  8. 代码重启SQL命令
  9. 庞锋 OpenCV 视频 学习进度备忘
  10. [反汇编练习] 160个CrackMe之015
  11. php 返回json 解析 报Wide character in print
  12. [转]getResource()和getResourceAsStream以及路径问题
  13. C++重载赋值运算符
  14. js,jQuery和DOM操作的总结(二)
  15. Linux iostat 命令
  16. Sharepoint 性能之SQL Server内存设置
  17. 一句话说清楚cache和buffer
  18. 修改windows默认的远程连接端口
  19. [转]TF-IDF与余弦相似性的应用(一):自动提取关键词
  20. 在 arc里面打印 引用计数的方法

热门文章

  1. 虚拟机克隆CentOs后网卡问题
  2. Ubuntu安装netdata监控平台
  3. 微信小程序入门学习之事件 事件对象 冒泡非冒泡事件(1)
  4. lintcode101 删除排序数组中的重复数字 II
  5. JavaScript 正则
  6. usdt信息小结
  7. iconFont 阿里巴巴矢量图标使用方法
  8. Python的实现分类
  9. 单源最短路——SPFA算法(Bellman-Ford算法队列优化)
  10. dataTables工作总结