poj 1741 Tree(点分治)

题目链接:http://poj.org/problem?id=1741

 

题解:一道点分治的模版题,直线上的分治就没什么好说了简单的这是一道树上的分治模版题

其实分治就是和二分差不多,树上的分治也就是不断的找树的重心然后再找经过重心的有几条路是满足条件的。树上的分治有具体的解析可以去看看理解一下挺简单的,然后差不多树上的分治都可以利用这个模版然后稍微改一下就好。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int M = 1e4 + 10;
struct Edge {
    int u , v , w , next;
}edge[M << 1];
int head[M] , e , Size , n , ans , k;
bool vis[M];
void init() {
    memset(head , -1 , sizeof(head));
    memset(vis , false , sizeof(vis));
    ans = e = 0;
}
void add(int u , int v , int w) {
    edge[e].v = v;
    edge[e].next = head[u];
    edge[e].w = w;
    head[u] = e++;
}
int size[M] , root , mx[M];
//////
void dfs_size(int u , int fa)
{
    size[u] = 1;
    mx[u] = 0;
    for(int i = head[u] ; ~i ; i = edge[i].next) {
        int v = edge[i].v;
        if(v != fa && !vis[v])
        {
            dfs_size(v, u);
            size[u] += size[v];
            if(size[v] > mx[u]) mx[u] = size[v];
        }
    }
}//找子树包括自生的个数
void dfs_root(int r, int u, int fa) {
    if(size[r] - size[u] > mx[u]) mx[u] = size[r] - size[u];
    if(mx[u] < Size) Size = mx[u], root = u;
    for(int i = head[u] ; ~i ; i = edge[i].next) {
        int v = edge[i].v;
        if(v != fa && !vis[v]) dfs_root(r, v, u);
    }
}//找重心
void get_root(int u , int pre) {
    dfs_size(u , pre);
    dfs_root(u , u , pre);
}
//////
int num = 0 , dis[M];
void find_dis(int u , int pre , int deep) {
    dis[num++] = deep;
    for(int i = head[u] ; ~i ; i = edge[i].next) {
        int v = edge[i].v;
        if(vis[v] || v == pre) continue;
        find_dis(v , u , deep + edge[i].w);
    }
}
int cau(int u , int pre , int deep) {
    num = 0;
    find_dis(u , pre , deep);
    int sum = 0;
    sort(dis , dis + num);
    int l = 0 , r = num - 1;
    while(l < r) {
        while(dis[l] + dis[r] > k && l < r) r--;
        sum += (r - l);
        l++;
    }
    return sum;
}//这里的cau只要改一下就能解其他类似的点分治问题
void dfs(int u) {
    Size = n;
    get_root(u , -1);
    vis[root] = true;
    ans += cau(root , -1 , 0);
    int rt = root;
    for(int i = head[root] ; ~i ; i = edge[i].next) {
        int v = edge[i].v;
        if(vis[v]) continue;
        ans -= cau(v , rt , edge[i].w);//这里为什么减去要理解一下然后就没什么问题了
        dfs(v);
    }
}
int main() {
    while(~scanf("%d%d" , &n , &k)) {
        if(n == 0 && k == 0) break;
        init();
        for(int i = 0 ; i < n - 1 ; i++) {
            int u , v , l;
            scanf("%d%d%d" , &u , &v , &l);
            add(u , v , l);
            add(v , u , l);
        }
        dfs(1);
        printf("%d\n" , ans);
    }
    return 0;
}

 

posted @ 2017-10-27 22:04  Gealo  阅读(153)  评论(0编辑  收藏  举报