ZOJ3632 线段树+DP

买西瓜吃,每个西瓜有两个参数,一个是p代表价格,一个是t代表能吃几天,要求n天每天都能吃西瓜,而且如果你今天买了,以前买的还没吃完 那么都得扔了,求最小花费,还真想不到用线段树+DP,最后看了一下别人的标题,想了一下,DP方程挺好推的,线段树也只是单点查询,

#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
//#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>

#define ll long long

#define eps 1e-8

#define inf 0xfffffff

const ll INF = 1ll<<61;

using namespace std;

//vector<pair<int,int> > G;
//typedef pair<int,int > P;
//vector<pair<int,int> > ::iterator iter;
//
//map<ll,int >mp;
//map<ll,int >::iterator p;

const int N = 50005   + 5;

typedef struct Node {
	int l,r;
	int mark;//biaoji
	ll pri;
};

Node tree[N << 2];

ll p[N],t[N];

void build(int l,int r,int id) {
	tree[id].l = l;
	tree[id].r = r;
	tree[id].mark = 0;
	tree[id].pri = INF;
	if(l == r)return;
	int mid = (l + r)>>1;
	build(l,mid,id<<1);
	build(mid+1,r,id<<1|1);
}

void push_up(int id) {
	if(tree[id].mark) {
		tree[id<<1].mark = 1;
		tree[id<<1|1].mark = 1;
		tree[id].mark = 0;

		tree[id<<1].pri = min(tree[id].pri,tree[id<<1].pri);
		tree[id<<1|1].pri = min(tree[id].pri,tree[id<<1|1].pri);
	}
}

void update(int l,int r,int id,ll cost) {
	if(l <= tree[id].l && r >= tree[id].r) {
		tree[id].pri = min(tree[id].pri,cost);
		tree[id].mark = 1;return ;
	}
	push_up(id);
	int mid = (tree[id].l + tree[id].r)>>1;
	if(r <= mid)update(l,r,id<<1,cost);
	else if(l > mid)update(l,r,id<<1|1,cost);
	else {
		update(l,mid,id<<1,cost);
		update(mid+1,r,id<<1|1,cost);
	}
}

ll query(int pos,int id) {
	if(pos == 0)return 0;
	if(tree[id].l == tree[id].r)
		return tree[id].pri;
	push_up(id);
	int mid = (tree[id].l + tree[id].r)>>1;
	if(pos <= mid) return query(pos,id<<1);
	else return query(pos,id<<1|1);
}

int main() {
	int n;
	while(scanf("%d",&n) == 1) {
		for(int i=1;i<=n;i++)
			scanf("%lld",&p[i]);
		for(int i=1;i<=n;i++)
			scanf("%lld",&t[i]);
		build(1,n,1);
		for(int i=1;i<=n;i++) {
			ll tmp = query(i-1,1);
			update(1,i + t[i] - 1,1,tmp + p[i]);
		}
		ll ans = query(n,1);
		printf("%lld\n",ans);
	}
	return 0;
}

ZOJ3632 线段树+DP,布布扣,bubuko.com

时间: 2024-12-20 07:19:51

ZOJ3632 线段树+DP的相关文章

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

HDU6447 YJJ&#39;s Salesman 2018中国大学生程序设计竞赛 - 网络选拔赛1010 离散化+线段树+DP

YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 253    Accepted Submission(s): 62 Problem Description YJJ is a salesman who has traveled through western country. YJJ is always on

[HDU 6447][YJJ&#39;s Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]

链接: http://acm.hdu.edu.cn/showproblem.php?pid=6447 题意: 左上角(0,0),右下角(10^9,10^9)的网格,其中有n(1<=n<=10^5)个方格内有权值. 一次只能沿右,下,右下三个方向走一个格子,只有沿右下方向走到格子里才可以获得权值. 问从(0,0)到(10^9,10^9)的路径最大权值是多少. 思路: 网格路径权值问题,第一感考虑DP,x从上往下,y从左往右刷表,状态转移方程为dp[i][j]=max(dp[i-1][j],dp[

CF932F(李超线段树+dp)

CF932F(李超线段树+dp) 此题又是新玩法, 李超线段树合并优化\(dp\) 一个显然的\(\Theta(n^2)dp\): \(dp[x]\)表示从x出发到叶子节点的最小代价 \(dp[x] = \min(dp[y] + a[x] * b[y]) ~~(y \in subtree(x))\) 如果我们将\(b[y]\)看成斜率, \(dp[y]\)看成纵截距, \(a[x]\)看成横坐标, 那么问题转为了在平面上有一些直线, 选出与直线\(x = a[x]\)相交的最靠下的点吗, 李超线

ZOJ-3632 Watermelon Full of Water 线段树+DP

暑假生活开始了,夏日炎炎,集训队想要每天都吃到西瓜.已知n天,每天商店提供一个西瓜,不同的西瓜可以供集训队吃不同的天数,也有不同的价格,问集训队想保证每天都能吃到西瓜的最小花费. 单个数100000,数组大小50000,因此需要用线段树优化. 对于每天的西瓜,不取则从最小值数组里取出当前最小值,取的话则是找出最小值+当天的西瓜价格,并且线段树更新后k天的最小费用. dp[i][1]=min(dp[i-1][0],dp[i-1][1])+v[i]; dp[i][0]=query(i,i,1,n,1

【BZOJ1835】[ZJOI2010]base 基站选址 线段树+DP

[BZOJ1835][ZJOI2010]base 基站选址 Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了.如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi.现在的问题是,选择基站的位置,使得总费用最小. 输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述. 第

hdu4521(线段树+dp)

传送门:小明系列问题——小明序列 题意:有n个数,求间距大于d的最长上升序列. 分析:dp[i]表示在i点以a[i]结束距离大于d的最长上升序列,然后每更新到第i点时,取i-d之前小于a[i]的数为结束的最长上升序列进行状态转移,并维护前i-d之前的最大上升序列,维护i-d之前的每点为结束的最长上升序列用线段树维护即可. #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #inc

lightoj1085 线段树+dp

1 //Accepted 7552 KB 844 ms 2 //dp[i]=sum(dp[j])+1 j<i && a[j]<a[i] 3 //可以用线段树求所用小于a[i]的dp[j]的和 4 //需要离散化 5 #include <cstdio> 6 #include <cstring> 7 #include <iostream> 8 #include <queue> 9 #include <cmath> 10 #

codeforces#426(div1) B - The Bakery (线段树 + dp)

题意:把 n 个数划分成 m 段,要求每组数不相等的数的数量最大之和. 思路: dp方程 : dp[i][j] = max( dp[k][j-1] + v(k, i) );( j<=k<i , k = j, j+1, +...+ i-1) dp[i][j]表示第 i 个数分到第 j 段的最大值. v(k, i) 表示k~i中不同数的个数,此处用hash记录每个数上一次出现的位置,从上一次出现的位置到当前位置的 dp[i][j-1] 值均可+1. 此时时间复杂度 O(n*m*log(n)). 线