zoukankan      html  css  js  c++  java
  • hdu4123-Bob’s Race(树形dp+rmq+尺取)

    题意:Bob想要开一个运动会,有n个房子和n-1条路(一棵树),Bob希望每个人都从不同的房子开始跑,要求跑的尽可能远,而且每条路只能走最多一次。Bob希望所有人跑的距离的极差不大于q,如果起点的编号需要连续,那么最多多少个起点。

    题解:首先求出每个点所能跑的最大距离(参考hdu2196),问题将转化成给n个数字,求差值不超过q的最大区间。m个询问,n个数,N<=50000 M<=500,所以对于每一次询问可以在O(n)的复杂度求解,st算法求区间最大最小值,尺取法求最大长度。

    (去年做2196的时候做了两三天,这次一下就写出来了,而且没怎么调,1A,开心^_^

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int N = 50005;
    const int INF = 0x5f5f5f5f;
    struct Edge {
        int to, cost, next;
    } edge[N*2];
    int head[N];
    int cnt_edge;
    void add_edge(int u, int v, int c) {
        edge[cnt_edge].to = v;
        edge[cnt_edge].cost = c;
        edge[cnt_edge].next = head[u];
        head[u] = cnt_edge++;
    }
    
    int d[N], mx[N], smx[N], mid[N], smid[N];
    void dfs(int u, int fa) {
        smx[u] = mx[u] = 0;
        mid[u] = smid[u] = 0;
        for (int i = head[u]; ~i; i = edge[i].next) {
            int v = edge[i].to;
            int c = edge[i].cost;
            if (v == fa) continue;
            dfs(v, u);
            if (mx[v]+c > smx[u]) {
                smx[u] = mx[v]+c;
                smid[u] = v;
            }
            if (smx[u] > mx[u]) {
                swap(smx[u], mx[u]);
                swap(smid[u], mid[u]);
            }
        }
    }
    int ans[N];
    void dfs(int u, int fa, int x) {
    
        if (fa == -1) { //没有父亲结点 向下的最大值就是最大值
            d[u] = 0;
        } else if (mid[fa] == u) {
            d[u] = max(x+smx[fa], d[fa]+x);
        } else {
            d[u] = max(x+mx[fa], d[fa]+x);
        }
        ans[u] = max(d[u], mx[u]);
    
        for (int i = head[u]; ~i; i = edge[i].next) {
            int v = edge[i].to;
            int c = edge[i].cost;
            if (v == fa) continue;
            dfs(v, u, c);
        }
    }
    
    int f1[N][20], f2[N][20];
    void init(int n)
    {
        // f[i,j]表示[i,i+2^j-1]区间最大值
        // f[i,j]=max(d[i,j-1], d[i+2^(j-1),j-1])
        for (int i = 1; i <= n; ++i) f2[i][0] = f1[i][0] = ans[i];
        for (int j = 1; (1<<j) <= n; ++j)
            for (int i = 1; i+j-1 <= n; ++i) {
                f1[i][j] = max(f1[i][j-1], f1[i+(1<<j-1)][j-1]);
                f2[i][j] = min(f2[i][j-1], f2[i+(1<<j-1)][j-1]);
            }
    }
    
    int query(int l, int r)
    {
        int k = 0;
        while (1<<k+1 <= r-l+1) ++k;
        return max(f1[l][k], f1[r-(1<<k)+1][k]) - min(f2[l][k], f2[r-(1<<k)+1][k]);
    }
    
    int main() {
        int n, m;
        while (~scanf("%d%d", &n, &m) && n) {
            int u, v, c;
            memset(head, -1, sizeof head);
            cnt_edge = 0;
            for (int i = 1; i < n; ++i) {
                scanf("%d%d%d", &u, &v, &c);
                add_edge(u, v, c);
                add_edge(v, u, c);
            }
            //10000000 q
            dfs(1, -1);
            dfs(1, -1, 0);
            //for (int i = 1; i <= n; ++i) printf("d[%d]=%d
    ", i, ans[i]);
            init(n);
            while (m--) {
                int q; scanf("%d", &q);
                int r = 1;
                int res = 0;
                for (int i = 1; i <= n; ++i) {
                    while (r <= n && query(i, r) <= q) r++;
                    res = max(res, r-i);
                }
                printf("%d
    ", res);
            }
        }
        return 0;
    }
  • 相关阅读:
    mysql install steps
    d3js
    js布局库
    mac 学习笔记
    js图形库
    zeromq 笔记
    C语言程序员必读的5本书
    Java基础
    JS中的toString方法
    给你六种面额1 5 10 20 50 100元的纸币假设每种币值的数量足够多
  • 原文地址:https://www.cnblogs.com/wenruo/p/5824703.html
Copyright © 2011-2022 走看看