Description
给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K
Input
N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k
Output
一行,有多少对点之间的距离小于等于k
Sample Input
7
1 6 13
6 3 9
3 5 7
4 1 3
2 4 20
4 7 2
10
Sample Output
5
HINT
Source
分析:
点分治
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=40010;
int st[N],tot=0,f[N],deep[N],sz[N],d[N],tt,n,m;
bool vis[N];
struct node{
int x,y,v,nxt;
};
node way[N<<1];
int root,sum,ans;
void add(int u,int w,int z)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}
void getroot(int now,int fa)
{
sz[now]=1;
f[now]=0;
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa&&!vis[way[i].y])
{
getroot(way[i].y,now);
sz[now]+=sz[way[i].y];
f[now]=max(f[now],sz[way[i].y]);
}
f[now]=max(f[now],sum-sz[now]);
if (f[now]<f[root]) root=now;
}
void getdeep(int now,int fa)
{
d[++tt]=deep[now];
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa&&!vis[way[i].y])
{
deep[way[i].y]=deep[now]+way[i].v;
getdeep(way[i].y,now);
}
}
int cal(int now)
{
tt=0;
getdeep(now,0);
sort(d+1,d+1+tt);
int ans=0;
int l=1,r=tt;
while (l<r)
{
if (d[l]+d[r]<=m) ans+=(r-l),l++;
else r--;
}
return ans;
}
void dfs(int now)
{
vis[now]=1;
deep[now]=0;
ans+=cal(now);
for (int i=st[now];i;i=way[i].nxt)
if (!vis[way[i].y])
{
deep[way[i].y]=way[i].v;
ans-=cal(way[i].y);
sum=sz[way[i].y]; root=0;
getroot(way[i].y,0);
dfs(root);
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;i++)
{
int u,w,z;
scanf("%d%d%d",&u,&w,&z);
add(u,w,z); add(w,u,z);
}
scanf("%d",&m);
root=0; f[0]=N; sum=n;
getroot(1,0);
ans=0;
dfs(root);
printf("%d",ans);
return 0;
}