POJ 1741 Tree 树分治

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

题意:

  给你一个含有n个节点的树,每条边有权值,问你有多少点对最短路径不超过k

 

题解:

  树分治入门题

  推荐看09年ioi的论文

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e5+20, M = 1e2+10, mod = 1e9+7, inf = 1e9+1000;
typedef long long ll;

int n,m,root,t,ans,allnode,siz[N],K,head[N],vis[N],d[N];
int deep[N];//路径长度//deep[0]子节点个数
int f[N];//重心

struct edg{int to,next,v;}e[N * 4];//前向星存边
void add(int u,int v,int w) {e[t].to=v;e[t].next=head[u];e[t].v=w;head[u]=t++;}//加边

//获取重心
void getroot(int x,int fa) {
    siz[x] = 1;
    f[x] = 0;
    for(int i=head[x];i;i=e[i].next) {
        int to = e[i].to;
        if(to == fa || vis[to]) continue;
        getroot(to,x);
        siz[x] += siz[to];
        f[x] = max(f[x] , siz[to]);
    }
    f[x] = max(allnode-siz[x] , f[x]);
    if(f[x] < f[root]) root = x;
}

void getdeep(int x,int fa) {//获取子树所有节点与根的距离
    deep[++deep[0]] = d[x];
    for(int i=head[x];i;i=e[i].next) {
        int to = e[i].to;
        if(to == fa || vis[to]) continue;
        d[to] = d[x] + e[i].v;
        getdeep(to,x);
    }
}
int cal(int x,int now) {//计算当前以重心x的子树下,所有情况的答案
    d[x]=now;deep[0]=0;
    getdeep(x,0);
    sort(deep+1,deep+deep[0]+1);
    int all = 0;
    for(int l=1,r=deep[0];l<r;) {
        if(deep[l]+deep[r] <= K) {all += r-l;l++;}
        else r--;
    }
    return all;
}

void work(int x) {//以x为重心进行计算
    vis[x] = 1;
    ans+=cal(x,0);
    for(int i=head[x];i;i=e[i].next) {
        int to = e[i].to;
        if(vis[to]) continue;
        ans -= cal(to,e[i].v);
        allnode = siz[to];
        root=0;
        getroot(to,x);
        work(root);
    }
}

int main()
{
    while(~scanf("%d%d",&n,&K)) {
        if(!n&&!m) break;
        memset(head,0,sizeof(head));
        memset(vis,0,sizeof(vis));
        t = 1;
        for(int i=1;i<n;i++) {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c) , add(b,a,c);
        }
        root=ans=0;
        allnode=n;f[0]=inf;
        getroot(1,0);
        work(root);
        printf("%d\n",ans);
    }
}

 

 

 

posted @ 2016-07-21 18:00  meekyan  阅读(256)  评论(0编辑  收藏  举报