【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;
}