zoukankan      html  css  js  c++  java
  • 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
    " , ans);
        }
        return 0;
    }
  • 相关阅读:
    day39——多线程实例、多线程锁
    day38——多进程Manager、进程池
    day37——多进程锁、多进程共享内存
    day36——多进程多线程概念、多进程、多进程实例
    day35——memcache常用方法
    day34——memcached安装、memcached集群操作
    day33——hash类型操作、其他常用操作
    day25——NoSQL的字符串操作、list操作、set操作
    day24——NoSQL简介、redis服务搭建、redis连接池、redis管道
    Linux日常巡检脚本
  • 原文地址:https://www.cnblogs.com/TnT2333333/p/7745400.html
Copyright © 2011-2022 走看看