POJ 1741Tree(树分治)

Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 15035   Accepted: 4902

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



解题思路:

   树分治:就是将一棵树以重心分成若干个树。然后分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;
}
}

你可能感兴趣的:(POJ 1741Tree(树分治))