zoukankan      html  css  js  c++  java
  • 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;
    }
    


  • 相关阅读:
    HDU 1124 Factorial
    hdu 1690 Bus System
    hdu 1113 Word Amalgamation
    POJ 2482 Stars in Your Window
    hdu 1385 ZOJ 1456 Minimum Transport Cost(经典floyd)
    hdu 1907 John
    VMware 虚拟机 安装 UBuntu 9.10 命令模式转换成窗口模试
    #pragma CODE_SEG __NEAR_SEG NON_BANKED详解
    Ubuntu 下Hadoop 伪分布式 hadoop0.20.2.tar.gz 的安装
    文件拷贝代码以及疑问
  • 原文地址:https://www.cnblogs.com/riskyer/p/3262930.html
Copyright © 2011-2022 走看看