Evanyou Blog 彩带

  题目传送门

Tree

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 30475   Accepted: 10232

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

  分析:

  点分治的入门题,不过也还是有点难度的。

  首先我们先找出树的重心,然后把它作为根节点算出它的子树中每一个点到它的距离,然后求出答案,但是这样求出的答案是有问题的,因为这样求出来的两点的距离可能会重复经过一条边两次,所以需要进行容斥。所以就递归调用,每次统计完答案以后减去子树可以得到的答案,然后再对子树进行同样的操作。

  讲的比较抽象,可以结合代码理解。

  Code:

//It is made by HolseLee on 17th Oct 2018
//POJ1741
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=5e4+7;
const int inf=1e9+7;
int n,K,dis[N],sim[N],mxson[N],head[N],cnte,root,S,MX,summer;
long long ans;
bool vis[N];
struct Edge {
    int to,nxt,val;
}e[N<<1];

inline int read()
{
    char ch=getchar(); int num=0; bool flag=false;
    while( ch<'0' || ch>'9' ) {
        if( ch=='-' ) flag=false; ch=getchar();
    }
    while( ch>='0' && ch<='9' ) {
        num=num*10+ch-'0'; ch=getchar();
    }
    return flag ? -num : num;
}

void print(int x)
{
    if( x>9 ) print(x/10);
    putchar(x%10+'0');
}

inline void add(int x,int y,int z)
{
    e[++cnte].to=y;
    e[cnte].val=z;
    e[cnte].nxt=head[x];
    head[x]=cnte;
}

void getroot(int x,int fa)
{
    sim[x]=1, mxson[x]=0;
    for(int i=head[x],y; i; i=e[i].nxt) {
        y=e[i].to;
        if( y==fa || vis[x] ) continue;
        getroot(y,x);
        sim[x]+=sim[y];
        mxson[x]=max(mxson[x],sim[y]);
    }
    mxson[x]=max(mxson[x],S-sim[x]);
    if( mxson[x]<MX ) { MX=mxson[x]; root=x; }
}

void getdis(int x,int fa,int dist)
{
    dis[++summer]=dist;
    for(int i=head[x],y; i; i=e[i].nxt) {
        y=e[i].to;
        if( y==fa || vis[y] ) continue;
        getdis(y,x,dist+e[i].val);
    }
}

inline int work(int x,int len)
{
    summer=0;
    memset(dis,0,sizeof(dis));
    getdis(x,0,len);
    sort(dis+1,dis+summer+1);
    int l=1, r=summer, ret=0;
    while( l<r ) {
        if( dis[l]+dis[r]<=K ) { ret+=(r-l); l++; }
        else r--;
    }
    return ret;
}

void divide(int x)
{
    ans+=work(x,0);
    vis[x]=1;
    for(int i=head[x],y; i; i=e[i].nxt) {
        y=e[i].to;
        if( vis[y] ) continue;
        ans-=work(y,e[i].val);
        S=sim[y]; root=0; MX=inf; 
        getroot(y,0); divide(root);
    }
}

int main()
{
    while( 1 ) {
        n=read(), K=read();
        if( !n && !K ) break;
        int x,y,z; cnte=ans=0;
        for(int i=1; i<=n; ++i) head[i]=0;
        for(int i=1; i<n; ++i) {
            x=read(); y=read(); z=read();
            add(x,y,z); add(y,x,z);
        }
        memset(vis,0,sizeof(vis));
        MX=inf; S=n; getroot(1,0);
        divide(root);
        print(ans); putchar('
');
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cytus/p/9807283.html