【树分治】 POJ 1741 Tree

来源:互联网 发布:艺人网络影响力榜2017 编辑:程序博客网 时间:2024/05/21 12:08
Tree
Time Limit: 1000MS Memory Limit: 30000KTotal Submissions: 17624 Accepted: 5757

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 41 2 31 3 11 4 23 5 10 0

Sample Output

8

Source

LouTiancheng@POJ



这道题的题意大致是说有一棵n个点的树,要我们求树上距离小于k的点对的个数。

首先看数据范围,n<=10000,n^2的做法基本不用去想了。
然后,这是一棵树,那么对于任意一个节点,通过这条线的节点必然在点的两侧。

那么,每一次我们找到一个点,然后把通过这个点的所有直线找出来,那么之后这个点就可以无视掉,然后再在拆开的两棵子树中寻找一个点,以此类推。
在另一篇博客中咱介绍到了树的重心的内容,由树的重心的性质我们可知每次找重心可以达到最优的效果

然后我们找到重心之后,扫描点到其他点的连线长度。
求距离排序一遍O(nlogn)然后左右同时扫一遍O(n),容斥排掉两点在同一子树的情况即可。

代码如下:
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int MAXN=20010;const int MAXM=10010;int n,m,ans;int u[MAXN],v[MAXN],w[MAXN],nex[MAXN];int fir[MAXM];bool vis[MAXM];int e_max;void add_edge(int a,int b,int c){    int e=e_max++;    u[e]=a;    v[e]=b;    w[e]=c;    nex[e]=fir[a];    fir[a]=e;}int subtree[MAXM];int maxtree[MAXM];int pt;void DfsSon(int x,int father){//    cout<<x<<" "<<father<<endl;//    system("pause");    subtree[x]=0;    maxtree[x]=0;    for(int e=fir[x];~e;e=nex[e])    {        if(vis[v[e]] || v[e]==father) continue;        DfsSon(v[e],x);        subtree[x]+=subtree[v[e]]+1;        maxtree[x]=max(maxtree[x],subtree[v[e]]+1);    }}void DfsSize(int root,int x,int father){    maxtree[x]=max(maxtree[x],subtree[root]-subtree[x]);    if(maxtree[pt]>maxtree[x])    {        pt=x;    }    for(int e=fir[x];~e;e=nex[e])    {        if(vis[v[e]] || v[e]==father) continue;        DfsSize(root,v[e],x);    }}int colle[MAXM],cont;void DfsColle(int x,int father,int lenth){    colle[cont++]=lenth;    for(int e=fir[x];~e;e=nex[e])    {        if(vis[v[e]] || father==v[e]) continue;        DfsColle(v[e],x,lenth+w[e]);    }}int calc(int x,int lenth){    int tmp=0;    cont=0;    //colle[cont++]=0;    DfsColle(x,0,lenth);    sort(colle,colle+cont);//    cout<<"cont="<<cont;//    for(int i=0;i<cont;i++) printf(",%d",colle[i]);//    cout<<endl;    int l=0,r=cont-1;    while(l<r)    {        while(colle[l]+colle[r]>m && l<r) r--;        tmp+=r-l;        l++;    }    return tmp;}void Dfs(int x){    DfsSon(x,0);    pt=x;    DfsSize(x,x,0);    //cout<<"pt="<<pt<<endl;    ans+=calc(pt,0);    vis[pt]=1;    for(int e=fir[pt];~e;e=nex[e])    {        if(vis[v[e]]) continue;        ans-=calc(v[e],w[e]);        Dfs(v[e]);    }//    cout<<ans<<endl;}int main(){    while(~scanf("%d%d",&n,&m) && n)    {        e_max=0;        memset(fir,-1,sizeof fir);        memset(vis,0,sizeof vis);        for(int i=1;i<n;i++)        {            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            add_edge(u,v,w);            add_edge(v,u,w);        }        ans=0;        Dfs(1);        printf("%d\n",ans);    }    return 0;}






0 0
原创粉丝点击