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

273 篇文章 0 订阅
112 篇文章 0 订阅

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

分析:本题要找的最大的连续区间的长度L,使得这个区间中的f[i]值最大与最小之差<=Q。该区间不一定从1开始。

首先用DP求出f[i]f[i]即从i点出发能走的最长距离。

然后用RMQ来解决每个询问。

1.     求f[i]。求法请见HDU2196

http://blog.csdn.net/u013480600/article/details/21831363

2.    RMQ处理询问。假设对于当前询问为Q值,那么我们设定两个int指针lr,初值都为1,最终值为n(共n个节点)。

我们每次都检查从l开始,能到达的最远r点,使得getMaxlr-getMinlr)的值<=Q。我们每次都固定l,然后让r尽量往后走,只要距离差<=Q就行。如果距离差>Q了,那么表示r-1已经是当前l位置能走的最远距离了,用这个数据去更新ans。所以此时我们求出了当前l能到达的最远距离,接下来我们要求l+1能到达的最远距离,当左端点是l+1时,r肯定至少都要在左端点为l时右端点能达到的最远位置上,想想是不是?这样我们对于一个询问就能在On)时间内解决(因为RMQgetMax时间是O1))。

AC代码:1343ms

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN =50000+100;
int tot;
int longest[MAXN];
int dist[MAXN][3];
int f[MAXN];
int head[MAXN];
int n,m;
struct edge
{
    int to;
    int next;
    int w;
}edges[MAXN*2];
void add_edge(int u,int v,int w)
{
    edges[tot].to=v;
    edges[tot].w=w;
    edges[tot].next=head[u];
    head[u]=tot++;
}
int dfs1(int u,int fa)
{
    if(dist[u][0]>=0)return dist[u][0];
    dist[u][0]=dist[u][1]=dist[u][2]=longest[u]=0;
    for(int e=head[u];e!=-1;e=edges[e].next)
    {
        int v= edges[e].to;
        if(v==fa)continue;

        if(dist[u][0]<dfs1(v,u)+edges[e].w)
        {
            dist[u][1] = dist[u][0];
            longest[u]=v;
            dist[u][0]=dfs1(v,u)+edges[e].w;
        }
        else if(dist[u][1]<dfs1(v,u)+edges[e].w)
            dist[u][1] = dfs1(v,u)+edges[e].w;
    }
    return dist[u][0];
}
void dfs2(int u,int fa)
{
    for(int e=head[u];e!=-1;e=edges[e].next)
    {
        int v=edges[e].to;
        if(v==fa)continue;

        if(v==longest[u])dist[v][2]=max(dist[u][2],dist[u][1])+edges[e].w;
        else dist[v][2]=max(dist[u][2],dist[u][0])+edges[e].w;
        dfs2(v,u);
    }
}
int dmax[MAXN][20];
int dmin[MAXN][20];
int mm[MAXN];//mm[x]=j表数x最多取log2能到j,即2^j<=x但是2^(j+1)>x
void initRMQ(int n,int d[])
{
    mm[0]=-1;
    for(int i=1;i<=n;i++)
    {
        mm[i] = (i&(i-1))==0?mm[i-1]+1:mm[i-1];//当i&(i-1)==0时,i必定为1000000这种数
        dmax[i][0]=d[i];
        dmin[i][0]=d[i];
    }
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            dmax[i][j] = max(dmax[i][j-1] , dmax[i+(1<<(j-1))][j-1]);
            dmin[i][j] = min(dmin[i][j-1] , dmin[i+(1<<(j-1))][j-1]);
        }
}
int getRMQ(int L,int R)
{
    int k=mm[R-L+1];;
    return max(dmax[L][k] , dmax[R-(1<<k)+1][k]) - min(dmin[L][k] , dmin[R-(1<<k)+1][k]) ;
}

void solve(int q)
{
    int l=1,r=1;
    int ans=1;
    while(l<=n&&r<=n)
    {
        while(r<=n&&getRMQ(l,r)<=q)
        {
            r++;
        }
        ans = max(ans,r-l);
        l++;
    }
    printf("%d\n",ans);
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        if(n==0&&m==0)break;
        tot=0;
        memset(dist,-1,sizeof(dist));
        memset(head,-1,sizeof(head));
        for(int i=1;i<n;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        dfs1(1,-1);
        dfs2(1,-1);
        for(int i=1;i<=n;i++)
            f[i] = max(dist[i][0] , dist[i][2]);
        initRMQ(n,f);
        while(m--)
        {
            int q;
            scanf("%d",&q);
            solve(q);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值