【AT_dp_q】Flowers

简单动态规划。

\(f_i\) 表示选择 \(1\sim i\) 中若干花的最大价值,必须选 \(i\)

容易想到动态规划转移方程 \(f_i=\max\{f_j\}+\omega_i\mid j<i,h_j\le h_i\)

直接模拟是 \(O(n^2)\) 的,我们考虑优化动态规划转移方程。

发现 \(i\) 的枚举必不可少,那么考虑优化求 \(\max\{f_j\}\) 的复杂度。

单点修改,区间查,怎么做?

线段树。

在线段树上维护最大值,每次 query 区间 \([1,h_i]\) 的最大值即可。

最后输出 \(\max \{f_i\}\),没说以什么结尾。

通过记录

#include <stdio.h>
#define int long long//数据范围可知,要long long
#define lc(id) (id<<1)
#define rc(id) (id<<1|1)
int tree[4000005];
int i,n,val,ret;
int v[1000005],h[1000005];
inline int max(int x,int y)
{
	return x>y?x:y;
}
inline void push_up(int id)
{
	tree[id]=max(tree[lc(id)],tree[rc(id)]);
	return ;
}
inline void update(int id,int l,int r,int pos,int nxt)
{
	if(l==r&&l==pos)
	{
		tree[id]=nxt;
		return ;
	}
	int mid=l+r>>1;
	if(pos<=mid)
		update(lc(id),l,mid,pos,nxt);
	if(mid<pos)
		update(rc(id),mid+1,r,pos,nxt);
	push_up(id);
	return ;
}//将 pos 的值改为 nxt
inline int query(int id,int ql,int qr,int l,int r)
{
//	printf("%d %d %d %d %d\n",id,ql,qr,l,r);
	if(ql<=l&&r<=qr)
	{
		return tree[id];
	}
	int mid=l+r>>1,res=-1;
	if(ql<=mid)
		res=max(res,query(lc(id),ql,qr,l,mid));
	if(qr>mid)
		res=max(res,query(rc(id),ql,qr,mid+1,r));
	return res;
}//查询 [ql,qr] 最大值
signed main()
{
	int n;scanf("%lld",&n);
	for(i=1;i<=n;++i)
		scanf("%lld",h+i);
	for(i=1;i<=n;++i)
		scanf("%lld",v+i);
//	build(1,1,n);
//	此题比较特殊,节点初始均为0。
//	由于我的写法,可以不 build。
	for(i=1;i<=n;++i)
	{
		val=query(1,1,h[i],1,n)+v[i];//当前的 f[i]
		ret=max(ret,val);
		update(1,1,n,h[i],val);
	}
	printf("%lld",ret);
	return 0;
}
posted @ 2023-02-05 09:27  Syara  阅读(8)  评论(0编辑  收藏  举报