【poj1741】Tree

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的链有几条
题解
对于这题 可以对这个点延伸出的几棵子树各做一次dfs
记录子树中出现的距离值
对于一棵树的距离值数组
把它排序求一次ans1
再对每棵子树分别求一个自己对自己的ans2
ans1−∑ans2即为最后的ans

代码

#include<cstring>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 10005
int n,m,k,tot,cnt,rt,ans;
int size[N],ret[2*N],len[2*N],Next[2*N],Head[2*N];
int a[N],dis[N];
bool flag[N];
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
inline void ins(int u,int v,int l)
{
    tot++;
    ret[tot]=v;
    len[tot]=l;
    Next[tot]=Head[u];
    Head[u]=tot;
}
void find_pre(int u,int f)//预处理
{
    size[u]=1;
    for (int i=Head[u];i;i=Next[i])
    {
        int v=ret[i];
        if (v!=f&&!flag[v]) 
        {
            find_pre(v,u);
            size[u]+=size[v];   
        }
    }
}
int find_rt(int u,int f)//寻找重心
{
    for (int i=Head[u];i;i=Next[i])
    {
        int v=ret[i];
        if (v!=f&&!flag[v])
        {
            if (size[v]>size[rt]/2) return find_rt(v,u);
        }
    }
    return u;
}
void dfs(int u,int f)//计算点到根的距离
{
    for (int i=Head[u];i;i=Next[i])
    {
        int v=ret[i];
        if (v!=f&&!flag[v])
        {
            dis[v]=dis[u]+len[i];
            a[++cnt]=dis[v];
            dfs(v,u);
        }
    }
}
int cal(int RT,int d)//计算答案
{
    dis[RT]=d;
    cnt=1;
    a[1]=d;
    dfs(RT,0);
    sort(a+1,a+cnt+1);
    int t=0,l,r;
    for(l=1,r=cnt;l<r;)
    {
        if(a[l]+a[r]<=k){t+=r-l;l++;}
        else r--;
    }
    return t;
}
inline void solve(int RT)
{
    ans+=cal(RT,0);
    flag[RT]=1;
    for (int i=Head[RT];i;i=Next[i])
    {
        int v=ret[i];
        if (!flag[v])
        {
            ans-=cal(v,dis[v]);
            find_pre(v,0);
            rt=v;
            solve(find_rt(rt,0));
        }
    }
}
int main()
{
    n=read();k=read();
    while (n!=0&&k!=0)
    {
        tot=0;
        for (int i=1;i<=n;i++)
            flag[i]=Head[i]=0;
        for (int i=1;i<n;i++)
        {
            int u=read(),v=read(),l=read();
            ins(u,v,l);
            ins(v,u,l);
        } 
        find_pre(1,0);
        rt=1;
        ans=0;
        solve(find_rt(1,0));
        printf("%d\n",ans);
        n=read();k=read();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值