HDU 4123 - Bob’s Race(树形DP + RMQ)

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4123

题意:

给出一颗n个点的有边权的树,Q个询问,给出m,求出连续的最长区间,每个点能到达的最长路径,最大值与最小值得差小于等于m。

思路:

两个dfs,得到每个点可以到达的最大路径。O(n)。

RMQ 求区间最小值最大值。O(nlogn), 询问O(1).

AC.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
const int maxn = 5e4+5;
int n;

int tot, head[maxn];
struct Edge{
    int to, w, next;
}edge[maxn*2];
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

int dis1[maxn], dis2[maxn], to1[maxn], to2[maxn], tor[maxn];
void dfs(int u, int fa)
{
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to, w = edge[i].w;
        if(v == fa) continue;
        //pre[v] = u;
        tor[v] = tor[u] + w;

        dfs(v, u);

        if(dis1[v] + w > dis1[u]) {
            dis2[u] = dis1[u]; to2[u] = to1[u];
            dis1[u] = dis1[v] + w; to1[u] = v;

        }
        else if(dis1[v] + w > dis2[u] && dis1[v] + w <= dis1[u]) {
            dis2[u] = dis1[v] + w; to2[u] = v;
        }
    }
}

void dfs1(int u, int fa)
{
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to, w = edge[i].w;
        if(v == fa) continue;
        if(to1[u] == v) {
            if(dis1[v] < dis2[u] + w) {
                dis2[v] = dis1[v]; to2[v] = to1[v];
                dis1[v] = dis2[u] + w; to1[v] = u;
            }
            else if(dis2[u]+w > dis2[v]) {
                dis2[v] = dis2[u] + w; to2[v] = u;
            }
        }
        else {
            if(dis1[v] < dis1[u] + w) {
                dis2[v] = dis1[v]; to2[v] = to1[v];
                dis1[v] = dis1[u] + w; to1[v] = u;
            }
            else if(dis1[u]+w > dis2[v]) {
                dis2[v] = dis1[u] + w; to2[v] = u;
            }
        }
        dfs1(v, u);
    }
}
int a[maxn];

int dp1[maxn][20];
int dp2[maxn][20];
int mm[maxn];
void initRMQ(int n)
{
    mm[0] = -1;
    for(int i = 1;i <= n;i++)
    {
        mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
        dp1[i][0] = a[i];
        dp2[i][0] = a[i];
    }
    for(int j = 1;j <= mm[n];j++)
        for(int i = 1;i + (1<<j) - 1 <= n;i++)
        {
            dp1[i][j] = max(dp1[i][j-1],dp1[i + (1<<(j-1))][j-1]);
            dp2[i][j] = min(dp2[i][j-1],dp2[i + (1<<(j-1))][j-1]);
        }
}
int rmq(int x,int y)
{
    int k = mm[y-x+1];
    return max(dp1[x][k],dp1[y-(1<<k)+1][k]) - min(dp2[x][k],dp2[y-(1<<k)+1][k]);
}

int main()
{
    //freopen("in", "r", stdin);
    int m;
    while(~scanf("%d%d", &n, &m)) {
        if(n == 0 && m == 0) break;
        int u, v, w;
        init();
        for(int i = 1; i < n; ++i) {
            scanf("%d%d%d", &u, &v, &w);
            if(u > v) swap(u, v);
            addedge(u, v, w);
            addedge(v, u, w);
        }

        for(int i = 1; i <= n; ++i) {
            dis1[i] = dis2[i] = 0;
            to1[i] = to2[i] = 0;
            tor[i] = 0;
        }


        dfs(1, -1);
        dfs1(1, -1);

        for(int i = 1; i <= n; ++i) {
            dis1[i] = max(dis1[i], tor[i]);
        }
        for(int i = 1; i <= n; ++i) {
            a[i] = dis1[i];
        }
        initRMQ(n);
        int Q;
        while(m--)
        {
            scanf("%d",&Q);
            int ans = 0;
            int id = 1;
            for(int i = 1;i <= n;i++)
            {
                while(id <= i && rmq(id,i) > Q)id++;
                ans = max(ans,i-id+1);
            }
            printf("%d\n",ans);
        }

    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值