楼教主的男人八题之一。。。。
狂T了一天,最后以把x错打成i而结束了漫长的debug。。。。
这个题是我的第一个树分治
树分治其实就是分治思想在树上的应用,在这个题中具体点就是把一颗子树中的路径分别计算然后递归到子树中再经行下一步的计算直到子树只有一个点
这个操作是基于点的所以叫点分治
这个题要有一个基础就是poj1655求树的重心
如果不会看这里
这样的话我们从一开始的大树中选出重心,然后计算对ans的贡献,然后递归到好多个子树当中去就可以了
特别要注意的是,本题还有了一个双指针手法,具体的可以看代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define MAX 20009
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
int tot,to[MAX],value[MAX],head[MAX],next[MAX],q,u[MAX],n,k;
int done[MAX],size[MAX],num[MAX];
int t,ans=0;
struct wbysr
{
int dis,belong;
}a[MAX];
bool cmp(wbysr a1,wbysr a2)
{
return a1.dis<a2.dis;
}
void add(int from,int To,int weight)
{
tot++;
to[tot]=To;
value[tot]=weight;
next[tot]=head[from];
head[from]=tot;
}
void dfs(int x,int fa)
{
u[++q]=x;
size[x]=1;
num[x]=0;
for(int i=head[x];i!=-1;i=next[i])
if(!done[to[i]]&&to[i]!=fa)
dfs(to[i],x),size[x]+=size[to[i]],num[x]=max(num[x],size[to[i]]);
return;
}
int find(int x)
{
q=0;
dfs(x,0);
int Return=x,Min=0x7fffffff;
rep(i,1,q)
if(max(size[x]-size[u[i]],num[u[i]])<Min)
Min=max(size[x]-size[u[i]],num[u[i]]),Return=u[i];
return Return;
}
void dfs2(int x,int fa,int dist,int Belong)
{
t++;
a[t].belong=Belong;
a[t].dis=dist;
for(int i=head[x];i!=-1;i=next[i])
if(to[i]!=fa&&!done[to[i]])
dfs2(to[i],x,dist+value[i],Belong);
}
void calc(int x)
{
t=0;
a[++t].belong=x;
a[t].dis=0;
for(int i=head[x];i!=-1;i=next[i])
if(!done[to[i]])
dfs2(to[i],x,value[i],to[i]);
sort(a+1,a+1+t,cmp);
int r=t,same[10009]={0};
rep(i,1,t)
same[a[i].belong]++;
for(int l=1;l<=t;l++)
{
while(a[l].dis+a[r].dis>k&&r>l)
same[a[r].belong]--,r--;
same[a[l].belong]--;
if(r>l)
ans+=r-l-same[a[l].belong];
}
}
inline void work(int x)
{
int root=find(x);
done[root]=1;
calc(root);
for(int i=head[root];i!=-1;i=next[i])
if(!done[to[i]])
work(to[i]);
return;
}
int main()
{
while(scanf("%d%d",&n,&k)&&n+k)
{
memset(done,0,sizeof(done));
memset(head,-1,sizeof(head));
ans=tot=0;
for(int i=1,a1,a2,a3;i<=n-1;i++)
scanf("%d%d%d",&a1,&a2,&a3),add(a1,a2,a3),add(a2,a1,a3);
work(1);
printf("%d\n",ans);
}
return 0;
}