码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 1741 男人八题——树分治

时间:2017-08-26 19:46:19      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:roo   arch   strong   ini   write   ons   count   pst   tput   

Tree
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 23829   Accepted: 7900

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

 
 
树分治:
分治很清楚是指分而治之,树就分成了子树,但是怎么分才能是的分才最适合呢? 
就像快速排序一样,也有可能退化,于是,用树的重心,这个DP很容易,但是,要每棵子树都要求重心呢?
 
以某一棵子树为研究对象,有多少个点对满足 d[i] + d[j] <= k 呢?
对这个子树 dfs求出 d ,距离 “根” 的距离(这个根是变化的);
将所有 d排序,扫描即可。
 
从根出发,递归到子节点,子节点再求,这样子节点求得的会有一部分重合。减去经过父亲结点的那些 <= k 的点对(此时,就是求以子节点为根,系数相差 d[f][v] 的 点对)。
 
至此,这个关于 点的 树分治,就解决了!!!
男人八题写了3题了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>


using namespace std;

#define N 10005

struct Node {
    int v,l;
};

vector<Node> g[N];

int n,k;

int s[N],f[N];
bool done[N];
int size;
int root;
void getroot(int u,int fa) {
    s[u] = 1;
    f[u] = 0;

    for(int i=0; i < (int)g[u].size(); i++) {
        int v = g[u][i].v;
        if(v!=fa&&!done[v]) {
            getroot(v,u);
            s[u] +=s[v];
            f[u] = max(f[u],s[v]);
        }
    }

    f[u] = max(f[u],size-s[u]);
    if(f[u]<f[root]) root = u;

}

vector<int> dep;
int d[N];
void getdep(int u,int fa) {

    dep.push_back(d[u]);
    s[u] = 1;

    for(int i=0; i < (int)g[u].size(); i++) {
        int v = g[u][i].v;
        if(v!=fa&&!done[v]) {
            d[v] = d[u] + g[u][i].l;
            getdep(v,u);
            s[u]+=s[v];
        }

    }

}

int calc(int u,int init) {
    dep.clear();
    d[u] = init;
    getdep(u,0);

    sort(dep.begin(),dep.end());

    int ret = 0;
    for(int l=0,r=dep.size()-1;l<r;)
        if(dep[l]+dep[r]<=k) ret += r-l++;
        else r--;
    return ret;
}

int ans;
void work(int u) {

    ans+=calc(u,0);
    done[u] = true;

    for(int i=0; i < (int)g[u].size(); i++) {
        int v = g[u][i].v;
        if(!done[v]) {
            ans-=calc(v,g[u][i].l);
            f[0] = size = s[v];
            getroot(v,root=0);
            work(root);
        }
    }

}

int main()
{
    while(scanf("%d%d",&n,&k),n) {

        for(int i=0; i <= n; i++) g[i].clear();

        memset(done,0,sizeof(done));

        int u,v,l;
        for(int i=1; i < n; i++) {
            scanf("%d%d%d",&u,&v,&l);
            g[u].push_back((Node){v,l});
            g[v].push_back((Node){u,l});
        }

        f[0] = size = n;
        getroot(1,root=0);
        ans = 0;
        work(root);

        printf("%d\n",ans);

    }
    return 0;
}

 

 
 
 
 
 
 

POJ 1741 男人八题——树分治

标签:roo   arch   strong   ini   write   ons   count   pst   tput   

原文地址:http://www.cnblogs.com/TreeDream/p/7436015.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!