【poj1741】【Tree】

Tree

Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 13068 Accepted: 4195
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

这道题是楼教主的男人八题
题意是这样的:给你一棵树,让你求出这棵树中的距离<=k的点对的数目。
这是一道点分的模板题,和聪聪可可一样,唯一不同的只是在calc上。
我们考虑我们已经得到了这棵树的子树中的点到重心的距离,那么我们怎样找到距离<=k的点对?
暴力枚举?? 显然会超时。
所以这道题的不同就是我们需要对于所有找到的距离进行排序。
这样我们从左右端点开始向中间找,如果遇到了某一段的左端点和右端点的和<=k,那么说明在这一段中的点都符合,就扩大左端点。
如果发现左端点于右端点的和大于k,就缩小右端点。
这样我们就可以统计出来了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10100;
const int inf=210000000;
int point[N],next[N*4],sum,son[N],n,k,root,f[N],deep[N],ans,dis[N],tot;
struct S{int st,en,va;}aa[N*4];
bool use[N];
inline void add(int x,int y,int z)
{
    tot+=1;next[tot]=point[x];point[x]=tot;
    aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;
    tot+=1;next[tot]=point[y];point[y]=tot;
    aa[tot].st=y;aa[tot].en=x;aa[tot].va=z;
}
/*-------找重心--------*/ 
inline void get_root(int x,int fa)
{
    int i,u;
    son[x]=1;f[x]=0;
    for(i=point[x];i;i=next[i])
      if(use[aa[i].en]&&aa[i].en!=fa){
        u=aa[i].en;
        get_root(u,x);
        son[x]+=son[u];
        f[x]=max(f[x],son[u]);
      }
    f[x]=max(f[x],sum-son[x]);
    if(f[x]<f[root]) root=x;
}
/*-------计算距离---------*/ 
inline void get_deep(int x,int fa)
{
    int i;
    deep[0]+=1;
    deep[deep[0]]=dis[x];
    for(i=point[x];i;i=next[i])
      if(use[aa[i].en]&&aa[i].en!=fa){
        dis[aa[i].en]=dis[x]+aa[i].va;
        get_deep(aa[i].en,x);
      }
}
/*---------分治-----------*/ 
inline int calc(int x,int now)
{
    deep[0]=0;dis[x]=now;
    get_deep(x,0);
    sort(deep+1,deep+deep[0]+1);
    int l=1,r=deep[0],all=0;
    while(l<=r){
        if(deep[l]+deep[r]<=k){
            all+=r-l;
            l+=1;
        }
        else r-=1;
    }
    return all;
}
inline void work(int x)
{
    int i;
    ans+=calc(x,0);
    use[x]=false;
    for(i=point[x];i;i=next[i])
      if(use[aa[i].en]){
        ans-=calc(aa[i].en,aa[i].va);
        root=0;
        sum=son[aa[i].en];
        get_root(aa[i].en,0);
        work(root);
      }
}
int main()
{
    int i,j,x,y,z;
    while(scanf("%d%d",&n,&k)==2){
        if(n==0&&k==0) break;
        tot=root=ans=0;     
        memset(son,0,sizeof(son));
        memset(use,1,sizeof(use));
        memset(point,0,sizeof(point));
        memset(next,0,sizeof(next));
        for(i=1;i<n;++i){
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
        }
        sum=n;f[0]=inf;
        get_root(1,0);
        work(root);
        printf("%d\n",ans);
    }
}

你可能感兴趣的:(【poj1741】【Tree】)