zoukankan      html  css  js  c++  java
  • [poj1741 Tree]树上点分治

    题意:给一个N个节点的带权树,求长度小于等于K的路径条数

    思路:选取一个点作为根root,假设f(root)是当前树的答案,那么答案来源于两部分:

    (1)路径不经过root,那么就是完全在子树内,这部分可以递归统计

    (2)路径经过root,这部分可以通过容斥原理统计,具体见有关点分治资料。。。

    点分治有个特点,当考虑的问题由根这个子树转为儿子的子树时,可以选取任意点作为新的根,只要它在儿子的子树内,这就使得我们可以通过选取特别的点使得树深度更小,这个点就是树的重心(在程序里面是不断找子树的重心),树分治的复杂度是O(NH+TH)的,其中H是树的深度,T是每层计算答案的复杂度,重心可以将树的深度变成O(logN)。

    另外,整体看树分治的遍历节点的过程,发现它与建堆的过程十分相似,也就从侧面说明了树分治的复杂度。。。

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <ctime>
    #include <map>
    #include <vector>
    using namespace std;
    #define X first
    #define Y second
    #define pb(x) push_back(x)
    #define mp(x, y) make_pair(x, y)
    #define all(a) (a).begin(), (a).end()
    #define mset(a, x) memset(a, x, sizeof(a))
    #define mcpy(a, b) memcpy(a, b, sizeof(b))
    #define cas() int T, cas = 0; cin >> T; while (T --)
    template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
    template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
    typedef long long ll;
    typedef pair<int, int> pii;
    
    #ifndef ONLINE_JUDGE
        #include "local.h"
    #endif
    
    const int N = 1e4 + 7;
    const int M = N;
    const int inf = 1e9 + 7;
    
    namespace Edge {
        int last[N], to[M << 1], w[M << 1], next[M << 1], cntE;
        void init() {
            cntE = 0;
            memset(last, -1, sizeof(last));
        }
        void addEdge(int u, int v, int w) {
            to[cntE] = v;
            Edge::w[cntE] = w;
            next[cntE] = last[u];
            last[u] = cntE ++;
        }
    }
    
    int n, K;
    
    namespace Center {
        int root, siz, son[N];
        void init() {
            siz = inf;
        }
        void getRoot(int cur, int fa, int total, bool used[]) {
            son[cur] = 0;
            int buf = 0;
            for (int i = Edge::last[cur]; ~i; i = Edge::next[i]) {
                int to = Edge::to[i];
                if (to != fa && !used[to]) {
                    getRoot(to, cur, total, used);
                    son[cur] += son[to] + 1;
                    buf = max(buf, son[to] + 1);
                }
            }
            buf = max(buf, total - son[cur] - 1);
            if (buf < siz || buf == siz && cur < siz) {
                siz = buf;
                root = cur;
            }
        }
    }
    
    void getDepth(int cur, int fa, int sum, vector<int> &vt, bool used[]) {
        vt.pb(sum);
        for (int i = Edge::last[cur]; ~i; i = Edge::next[i]) {
            int to = Edge::to[i], w = Edge::w[i];
            if (to != fa && !used[to]) getDepth(to, cur, sum + w, vt, used);
        }
    }
    
    int getAns(vector<int> &vt) {
        sort(all(vt));
        int maxp = vt.size() - 1, ans = 0;
        for (int i = 0; i < maxp; i ++) {
            while (i < maxp && vt[i] + vt[maxp] > K) maxp --;
            ans += maxp - i;
        }
        return ans;
    }
    
    bool used[N];
    
    int work(int cur) {
        used[cur] = true;
        vector<int> total;
        total.push_back(0);
        int ans = 0;
        for (int i = Edge::last[cur]; ~i; i = Edge::next[i]) {
            int to = Edge::to[i], w = Edge::w[i];
            if (!used[to]) {
                vector<int> local;
                getDepth(to, cur, w, local, used);
                ans -= getAns(local);
                for (int j = 0; j < local.size(); j ++) {
                    total.push_back(local[j]);
                }
                Center::init();
                Center::getRoot(to, cur, local.size(), used);
                ans += work(Center::root);
            }
        }
        return ans += getAns(total);
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
    #endif // ONLINE_JUDGE
        while (cin >> n >> K, n || K) {
            int u, v, w;
            Edge::init();
            Center::init();
            mset(used, 0);
            for (int i = 1; i < n; i ++) {
                scanf("%d%d%d", &u, &v, &w);
                Edge::addEdge(u, v, w);
                Edge::addEdge(v, u, w);
            }
            Center::getRoot(1, 0, n, used);
            cout << work(Center::root) << endl;
        }
        return 0;
    }
    

      

  • 相关阅读:
    hdu 3666 差分约束系统
    hdu 1198农田灌溉
    常微分方程(阿諾爾德) Page 45 相空間,相流,運動,相曲線 註記
    高等微積分(高木貞治) 1.4節 例2
    常微分方程(阿諾爾德) Page 45 相空間,相流,運動,相曲線 註記
    解析函數論 Page 29 命題(2) 函數模的有界性
    高等微積分(高木貞治) 1.4節 例2
    解析函數論 Page 29 命題(1) 有界閉集上的一致連續性
    解析函數論 Page 29 命題(3) 模的下界的可達性
    解析函數論 Page 29 命題(2) 函數模的有界性
  • 原文地址:https://www.cnblogs.com/jklongint/p/4960052.html
Copyright © 2011-2022 走看看