线段树
题意:给定n表示n天,第一行为n天每天西瓜价格,第二行为该天买的西瓜能吃的天数
问,每天都要有西瓜吃,到n天花的钱的最小值(注意,当买了第k天的西瓜,则之前的西瓜将被丢弃,也就是说,天数的计算取决于最后一次买的西瓜)
思路:
买或不买 第i天的西瓜, 则第i天的花费为
use[i] = Min( use[i-1] +today_price[i] , use [i] ); // 初始化每天花费为无穷大
这里用的是线段树做法,注意的是数据类型是 long long
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
#define N 50005
#define INF 1152921504606846976
#define R(x) x<<1|1
#define L(x) x<<1
#define Mid(x,y) (x+y)>>1
#define ll long long
using namespace std;
ll n,a[N],b[N];//dp[i][j]代表i点花了j天的最大值
struct node{
int r,l,lazy;
ll num;
}tree[N*4];
inline ll Max(ll a,ll b){return a>b?a:b;}
inline ll Min(ll a,ll b){return a<b?a:b;}
void build(int l,int r,int id){
tree[id].l=l; tree[id].r=r;
tree[id].lazy=0;
tree[id].num=INF; //
if(l==r)return ;
int mid=Mid(r,l);
build(l,mid,L(id)); build(mid+1,r,R(id));
}
void Lazy(int id){
if(tree[id].lazy){
tree[R(id)].lazy=1;
tree[L(id)].lazy=1;
tree[R(id)].num=Min(tree[id].num,tree[R(id)].num);
tree[L(id)].num=Min(tree[id].num,tree[L(id)].num);
tree[id].lazy=0; //这里lazy也可以用来存东西
}
}
void updata(int l,int r,int id,ll data){
if(l<=tree[id].l && tree[id].r<=r) //若当前树段在区间内 ,则更新当前整个树段并结束
{
tree[id].num=Min(tree[id].num, data);//根据情况改
tree[id].lazy=1; //这里是标记 若是1则下面的树段要更新lazy
return ;
}
Lazy(id); //这里
int mid=Mid(tree[id].l,tree[id].r);
if (l<=mid) updata(l,r,L(id),data);
if (r>mid) updata(l,r,R(id),data);
}
ll query(int pos,int id){//单点询问,询问pos点的值
if(pos==0)return 0;
if(tree[id].l==tree[id].r) return tree[id].num;
Lazy(id);
int mid=Mid(tree[id].l,tree[id].r);
if(pos<=mid)return query(pos,L(id));
else return query(pos,R(id));
}
int main(){
int i;
while(~scanf("%d",&n)){
for(i=1;i<=n;i++)scanf("%lld",&a[i]);
for(i=1;i<=n;i++)scanf("%lld",&b[i]);
build(1,n,1);
for(i=1;i<=n;i++)
{
ll temp=query(i-1,1);
updata(1,i+b[i]-1,1,temp+a[i]);//i-1天花的钱今天花的钱求最小
}
printf("%lld\n",query(n,1));
}
return 0;
}