• BZOJ 2599 [IOI2011]Race【Tree,点分治】


    给出N(1 <= N <= 200000)个结点的树,求长度等于K(1 <= K <= 1000000)的路径的最小边数。

    点分治,这道题目和POJ 2114很接近,2114是求是否存在长度为K的边,但是那个K比较大。但是这道题目的K比之小了10倍。

    1. 用V[i]表示到当前树根root的路径长度为i 时的点(赋值为root结点即可),这样就可以用来判断两条到根的路径长度之和是否等于K:

        结点a的root的距离为i,结点b到root的距离为j,处理完a之后会得到V[i] = root,那么在处理结点b的时候,如果V[K-j] = root,就说明某一个a和b的路径长度为K,此时,就可以更新最小边数了。

    2. e[i]表示到当前树根root的路径长度为i 时的边的最小条数。


    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <iostream>
    using namespace std;
    #define N 200010
    #define inf 0x3f3f3f3f
    struct node {
        int v, l;
        node() {}
        node(int _v, int _l): v(_v), l(_l) {};
    };
    vector<node> g[N];
    int n, K, cur, root, size, ans;
    int s[N], f[N], d[N], e[N];  //s子树的结点数,f求重心,d子结点到根的距离,e子结点到根的边数
    int v[N*10], c[N*10];
    bool done[N];
    
    void getroot(int now, int fa) {
        int u;
        s[now] = 1, f[now] = 0;
        for (int i=0; i<g[now].size(); i++)
            if ((u = g[now][i].v) != fa && !done[u]) {
                getroot(u, now);
                s[now] += s[u];
                f[now] = max(f[now], s[u]);
            }
        f[now] = max(f[now], size-s[now]);
        if (f[now] < f[root]) root = now;
    }
    void dfs1(int now, int fa) {
        if (d[now] > K) return ;
        if (v[K-d[now]] == cur) ans = min(ans, c[K-d[now]]+e[now]);
        int u;
        for (int i=0; i<g[now].size(); i++)
            if ((u = g[now][i].v) != fa && !done[u]) {
                d[u] = d[now] + g[now][i].l;
                e[u] = e[now] + 1;
                dfs1(u, now);
            }
    }
    void dfs2(int now, int fa) {
        if (d[now] > K) return ;
        if (v[d[now]] != cur) {
            c[d[now]] = e[now];
            v[d[now]] = cur;
        } else c[d[now]] = min(c[d[now]], e[now]);
        int u;
        for (int i=0; i<g[now].size(); i++)
            if ((u = g[now][i].v) != fa && !done[u])
                dfs2(u, now);
    }
    void work(int now) {
        v[0] = cur = now + 1;
        int u;
        for (int i=0; i<g[now].size(); i++)
            if (!done[u = g[now][i].v]) {
                d[u] = g[now][i].l;
                e[u] = 1;
                dfs1(u, now);
                dfs2(u, now);
            }
        getroot(now, n); //更新s数组
        done[now] = true;
        for (int i=0; i<g[now].size(); i++)
            if (!done[u = g[now][i].v]) {
                f[n] = size = s[u];
                getroot(u, root=n);
                work(root);
            }
    }
    int main() {
        scanf("%d%d", &n, &K);
        for (int i=0; i<=n; i++) g[i].clear();
    
        for (int i=1, a, b, c; i<n; i++) {
            scanf("%d%d%d", &a, &b, &c);
            g[a].push_back(node(b, c));
            g[b].push_back(node(a, c));
        }
        memset(done, false, sizeof(done));
    
        ans = f[n] = size = n;
        getroot(0, root=n);
        work(root);
    
        printf("%d
    ", ans < n ? ans : -1);
    
        return 0;
    }
    


  • 相关阅读:
    Java
    paratest
    ccnet
    资料
    ccnet
    判断类被某个属性应用
    有趣的数学 -- 数学归纳法 -- 互不重叠的单位正方形
    排序算法 -- 堆排序
    APUE CH10 Signals
    APUE CH9 Process Relationship
  • 原文地址:https://www.cnblogs.com/riskyer/p/3262930.html
Copyright © 2020-2023  润新知