Tree
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 13068 Accepted: 4195
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
这道题是楼教主的男人八题
题意是这样的:给你一棵树,让你求出这棵树中的距离<=k的点对的数目。
这是一道点分的模板题,和聪聪可可一样,唯一不同的只是在calc上。
我们考虑我们已经得到了这棵树的子树中的点到重心的距离,那么我们怎样找到距离<=k的点对?
暴力枚举?? 显然会超时。
所以这道题的不同就是我们需要对于所有找到的距离进行排序。
这样我们从左右端点开始向中间找,如果遇到了某一段的左端点和右端点的和<=k,那么说明在这一段中的点都符合,就扩大左端点。
如果发现左端点于右端点的和大于k,就缩小右端点。
这样我们就可以统计出来了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10100;
const int inf=210000000;
int point[N],next[N*4],sum,son[N],n,k,root,f[N],deep[N],ans,dis[N],tot;
struct S{int st,en,va;}aa[N*4];
bool use[N];
inline void add(int x,int y,int z)
{
tot+=1;next[tot]=point[x];point[x]=tot;
aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;
tot+=1;next[tot]=point[y];point[y]=tot;
aa[tot].st=y;aa[tot].en=x;aa[tot].va=z;
}
/*-------找重心--------*/
inline void get_root(int x,int fa)
{
int i,u;
son[x]=1;f[x]=0;
for(i=point[x];i;i=next[i])
if(use[aa[i].en]&&aa[i].en!=fa){
u=aa[i].en;
get_root(u,x);
son[x]+=son[u];
f[x]=max(f[x],son[u]);
}
f[x]=max(f[x],sum-son[x]);
if(f[x]<f[root]) root=x;
}
/*-------计算距离---------*/
inline void get_deep(int x,int fa)
{
int i;
deep[0]+=1;
deep[deep[0]]=dis[x];
for(i=point[x];i;i=next[i])
if(use[aa[i].en]&&aa[i].en!=fa){
dis[aa[i].en]=dis[x]+aa[i].va;
get_deep(aa[i].en,x);
}
}
/*---------分治-----------*/
inline int calc(int x,int now)
{
deep[0]=0;dis[x]=now;
get_deep(x,0);
sort(deep+1,deep+deep[0]+1);
int l=1,r=deep[0],all=0;
while(l<=r){
if(deep[l]+deep[r]<=k){
all+=r-l;
l+=1;
}
else r-=1;
}
return all;
}
inline void work(int x)
{
int i;
ans+=calc(x,0);
use[x]=false;
for(i=point[x];i;i=next[i])
if(use[aa[i].en]){
ans-=calc(aa[i].en,aa[i].va);
root=0;
sum=son[aa[i].en];
get_root(aa[i].en,0);
work(root);
}
}
int main()
{
int i,j,x,y,z;
while(scanf("%d%d",&n,&k)==2){
if(n==0&&k==0) break;
tot=root=ans=0;
memset(son,0,sizeof(son));
memset(use,1,sizeof(use));
memset(point,0,sizeof(point));
memset(next,0,sizeof(next));
for(i=1;i<n;++i){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
sum=n;f[0]=inf;
get_root(1,0);
work(root);
printf("%d\n",ans);
}
}