ZOJ 3632 Watermelon Full of Water(dp+线段树 单点修改)

本文介绍了一种算法,用于计算在一定天数内,每天都能以最小花费吃到西瓜的策略,通过线段树和单点更新维护最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

       一共有n天

        每天西瓜售价为dp[i]元

        该天的西瓜能吃v[i]天 而且这天如果买了西瓜之前的西瓜就要扔掉

        问每天都吃到西瓜的最小花费是多少

思路:

       从最后一天开始dp最小花费

       并用线段树单点更新来维护

 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define ll long long
#define INF 1e10
ll dp[50000+100];//从后往前 dp[i]必买西瓜的最小花费
int v[50000+100];
ll sum[200000+100];
int n;
void push(int rt)
{
    sum[rt]=min(sum[rt<<1],sum[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    sum[rt]=INF;
    if(l==r)
    {
       return ;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    push(rt);
}
void update(int key,ll add,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=min(sum[rt],add);
        return ;
    }
    int m=(l+r)>>1;
    if(key<=m) update(key,add,l,m,rt<<1);
    else update(key,add,m+1,r,rt<<1|1);
    push(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    ll res1=INF,res2=INF;
    int m=(l+r)>>1;
    if(L<=m)
    {
        res1=query(L,R,l,m,rt<<1);
    }
    if(R>m)
    {
        res2=query(L,R,m+1,r,rt<<1|1);
    }
    return min(res1,res2);
}
int main()
{
    int i,j,k;
    while(scanf("%d",&n)!=EOF)
    {
        build(1,n+1,1);
        for(i=1;i<=n;i++)
        {
            scanf("%lld",&dp[i]);
        }
        for(i=1;i<=n;i++)
        {
            scanf("%d",&v[i]);
        }
        dp[n+1]=0;
        update(n+1,dp[n+1],1,n+1,1);
        for(i=n;i>=1;i--)
        {
            int r=i+v[i];
            if(r>n+1) r=n+1;
            ll next=query(i+1,r,1,n+1,1);
            dp[i]+=next;
            update(i,dp[i],1,n+1,1);
        }
        
        printf("%lld\n",dp[1]);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/sola1994/p/4430152.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值