Tree
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 17624 | Accepted: 5757 |
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.
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.
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
这道题的题意大致是说有一棵n个点的树,要我们求树上距离小于k的点对的个数。
首先看数据范围,n<=10000,n^2的做法基本不用去想了。
然后,这是一棵树,那么对于任意一个节点,通过这条线的节点必然在点的两侧。
那么,每一次我们找到一个点,然后把通过这个点的所有直线找出来,那么之后这个点就可以无视掉,然后再在拆开的两棵子树中寻找一个点,以此类推。
在另一篇博客中咱介绍到了树的重心的内容,由树的重心的性质我们可知每次找重心可以达到最优的效果
然后我们找到重心之后,扫描点到其他点的连线长度。
求距离排序一遍O(nlogn)然后左右同时扫一遍O(n),容斥排掉两点在同一子树的情况即可。
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=20010;
const int MAXM=10010;
int n,m,ans;
int u[MAXN],v[MAXN],w[MAXN],nex[MAXN];
int fir[MAXM];
bool vis[MAXM];
int e_max;
void add_edge(int a,int b,int c)
{
int e=e_max++;
u[e]=a;
v[e]=b;
w[e]=c;
nex[e]=fir[a];
fir[a]=e;
}
int subtree[MAXM];
int maxtree[MAXM];
int pt;
void DfsSon(int x,int father)
{
// cout<<x<<" "<<father<<endl;
// system("pause");
subtree[x]=0;
maxtree[x]=0;
for(int e=fir[x];~e;e=nex[e])
{
if(vis[v[e]] || v[e]==father) continue;
DfsSon(v[e],x);
subtree[x]+=subtree[v[e]]+1;
maxtree[x]=max(maxtree[x],subtree[v[e]]+1);
}
}
void DfsSize(int root,int x,int father)
{
maxtree[x]=max(maxtree[x],subtree[root]-subtree[x]);
if(maxtree[pt]>maxtree[x])
{
pt=x;
}
for(int e=fir[x];~e;e=nex[e])
{
if(vis[v[e]] || v[e]==father) continue;
DfsSize(root,v[e],x);
}
}
int colle[MAXM],cont;
void DfsColle(int x,int father,int lenth)
{
colle[cont++]=lenth;
for(int e=fir[x];~e;e=nex[e])
{
if(vis[v[e]] || father==v[e]) continue;
DfsColle(v[e],x,lenth+w[e]);
}
}
int calc(int x,int lenth)
{
int tmp=0;
cont=0;
//colle[cont++]=0;
DfsColle(x,0,lenth);
sort(colle,colle+cont);
// cout<<"cont="<<cont;
// for(int i=0;i<cont;i++) printf(",%d",colle[i]);
// cout<<endl;
int l=0,r=cont-1;
while(l<r)
{
while(colle[l]+colle[r]>m && l<r) r--;
tmp+=r-l;
l++;
}
return tmp;
}
void Dfs(int x)
{
DfsSon(x,0);
pt=x;
DfsSize(x,x,0);
//cout<<"pt="<<pt<<endl;
ans+=calc(pt,0);
vis[pt]=1;
for(int e=fir[pt];~e;e=nex[e])
{
if(vis[v[e]]) continue;
ans-=calc(v[e],w[e]);
Dfs(v[e]);
}
// cout<<ans<<endl;
}
int main()
{
while(~scanf("%d%d",&n,&m) && n)
{
e_max=0;
memset(fir,-1,sizeof fir);
memset(vis,0,sizeof vis);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
ans=0;
Dfs(1);
printf("%d\n",ans);
}
return 0;
}