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;
}
原文地址:https://www.cnblogs.com/wenruo/p/5824703.html