POJ 1741(点分治)

Tree

Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 33152 Accepted: 11082

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

Source

LouTiancheng@POJ

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+9;

/***动态点分治**/

int n,m;

struct rt{
    int v,c,next;
}e[maxn*2];

int head[maxn],tot,cnt;
int sz[maxn],f[maxn],vis[maxn],dep[maxn],a[maxn];

void add(int u,int v,int c){
    e[tot].v=v;
    e[tot].c=c;
    e[tot].next=head[u];
    head[u]=tot++;
}

int root,sum;
int ans;

void get_root(int u,int fa){
    sz[u]=1;f[u]=0;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v==fa||vis[v])continue;
        get_root(v,u);
        sz[u]+=sz[v];
        f[u]=max(f[u],sz[v]);
    }
    f[u]=max(f[u],sum-sz[u]);
    if(f[u]<f[root])root=u;
}

void getdeep(int u,int fa){
    a[++cnt]=dep[u];
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v==fa||vis[v])continue;
        dep[v]=dep[u]+e[i].c;
        getdeep(v,u);
    }
}

int calc(int u,int w){
    cnt=0;dep[u]=w;
    getdeep(u,0);
    sort(a+1,a+1+cnt);
    int res=0;
    int l=1,r=cnt;
    while(l<r){
        if(a[l]+a[r]<=m)res+=r-l,l++;
        else r--;
    }
    return res;
}

void solve(int u){
    ans+=calc(u,0);
    vis[u]=1;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(vis[v])continue;
        ans-=calc(v,e[i].c);
        sum=sz[v];root=0;
        get_root(v,0);
        solve(root);
    }
}

int main(){
    while(~scanf("%d%d",&n,&m)&&(n+m)){
        for(int i=0;i<=n;i++)head[i]=-1,vis[i]=0;
        tot=0;
        int u,v,c;
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&u,&v,&c);
            add(u,v,c);
            add(v,u,c);
        }
        ans=0;
        root=0; f[0]=sum=n;
        get_root(1,0);
        solve(root);
        printf("%d\n",ans);
    }
    return 0;
}









 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值