Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 15035 | Accepted: 4902 |
Description
Input
Output
Sample Input
5 4 1 2 3 1 3 1 1 4 2 3 5 1 0 0
Sample Output
8
解题思路:
树分治:就是将一棵树以重心分成若干个树。然后分2种情况,一种是包括根,另一种是不包括根。 对于不包括的就可以进行分治。而对于包括的就先统计每个点(当前树的点)到root的距离,利用单调性,求出两两可以配对的,不过如果两个点在同一棵子树上时就要减掉,因为在接下去的分治中,它会被统计,所以为了避免统计,要减掉。对于不要的点对可以分别统计每棵子树包括的对数。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,opp;
long long sum=0;
int len=0;
struct data
{
int from,to,zhi,next;
}e[91009];
int h[11001];
int son[11001];
bool vis[11001];
int ma,root,ge;
int lg[11001];
void insert(int x,int y,int length){++len; e[len].from=x; e[len].to=y; e[len].zhi=length; e[len].next=h[x]; h[x]=len;}
int getroot(int o,int fa)
{
son[o]=1;
int u=h[o];
while (u!=0)
{
if (e[u].to!=fa && vis[e[u].to])
{
son[o]+=getroot(e[u].to,o);
}
u=e[u].next;
}
int zan=max(son[o]-1,opp-son[o]);
if (zan<ma){ma=zan;root=o;}
return son[o];
}
int getdeep(int now,int leng,int fa)
{
++ge;
lg[ge]=leng;
int u=h[now];
while (u!=0)
{
if (vis[e[u].to] && e[u].to!=fa)
{
getdeep(e[u].to,leng+e[u].zhi,now);
}
u=e[u].next;
}
}
int cal()
{
int t=0;
for (int l=1,r=ge;l<r;)
{
if (lg[l]+lg[r]<=m)
{
t+=r-l;++l;
}else
--r;
}
return t;
}
int work(int ro)
{
vis[ro]=false; ge=0;
getdeep(ro,0,0);
sort(lg+1,lg+ge+1);
sum+=cal();
int u=h[ro];
while (u!=0)
{
if (vis[e[u].to])
{
ge=0; getdeep(e[u].to,e[u].zhi,0);
sort(lg+1,lg+ge+1);
sum-=cal();
ma=0x7fffffff;
opp=son[e[u].to];
getroot(e[u].to,ro); work(root);
}
u=e[u].next;
}
}
int main()
{
while (scanf("%d %d",&n,&m) && n!=0 )
{
memset(h,0,sizeof(h)); len=0;
for (int i=1;i<=n-1;++i)
{
int x,y,length;
scanf("%d %d %d",&x,&y,&length);
insert(x,y,length); insert(y,x,length);
}
sum=0; ma=0x7fffffff; root=0; opp=n;
memset(vis,true,sizeof(vis));
getroot(1,0);
work(root);
cout<<sum<<endl;
}
}