最大权值(树状数组/线段树优化dp)
小明在校园里种了n棵树排成一排,第i棵树有两个属性,高度h[i],价值a[i],保证每棵树的高度不同,现在学校要砍伐一些树,使得剩余的树高度单调递增,并且剩余的树价值最大,问价值最大是多少。
输入格式
第一行一个整数n
第二行n个整数,表示h[1],h[2],...h[n]
第三行n个整数w[1],w[2],...w[n]
1<=n<=2e5,1<=h[i]<=n,1<=w[i]<=1e9
输出格式
一个整数
输入/输出例子1
输入:
4
3 1 4 2
10 20 30 40
输出:
60
输入/输出例子2
输入:
1
1
10
输出:
10
样例解释
无
dp优化:如果dp根据前一段dp值进行更新,然后要对当前点更新,也就是 dp[i]=dp[i-1]+.....,然后有限制条件,例如 a[i]<a[j],才能让i的值给j,考虑线段树/树状数组进行优化,下标对应的就是a的最大值,存的值就是最优的dp[i]
类似最长上升子序列,但是朴素dp,O(n^2)肯定会炸,这里放出朴素dp:
定f[i]:前i个数,留下的树高度单调上升,留下的树的价值的和的最大值
我们可以枚举一个j,j从1~i-1,限制:h[j] < h[i]
满足限制后,转移就是 f[i]=max(f[i], f[j]+w[i])
初始化:从第i棵树往后开始选,前面的一律不管了,也就是 f[i]=w[i]
答案就是1~n的最大f[i]
#include <bits/stdc++.h> using namespace std; const int N=2e5+5; int n, h[N], w[N]; long long f[N], ans=0; int main() { scanf("%d", &n); for (int i=1; i<=n; i++) scanf("%d", &h[i]); for (int i=1; i<=n; i++) scanf("%d", &w[i]); for (int i=1; i<=n; i++) { f[i]=w[i]; for (int j=i-1; j>=1; j--) if (h[j]<h[i]) f[i]=max(f[i], w[i]+f[j]); } for (int i=1; i<=n; i++) ans=max(ans, f[i]); printf("%lld", ans); return 0; } /* 7 1 5 2 6 3 7 4 60 80 20 100 90 40 20 7 1 5 2 6 3 7 4 60 80 20 100 90 40 20 280 */
发现这里无法对 i 这里做优化,那么只能对 j 做文章了
我们想要找到满足限制的前i-1个的f[j]的最大值,找到后对第i位修改
转换为区间查询,单点修改,线段树和树状数组都是可以的
这里用树状数组。
树状数组存的肯定是 f 的最大值嘛
不过这里下标对应的值将会有意义,下标的意义变成的树的高度(并且树的高度不是很大),那么这样转换,问题就迎刃而解了。
我们只需要找 1~h[i]-1 的区间内的最大值就是区间查询了。
那么单点修改也很简单了,把下标为 h[i] 的值更新一下最大值为 f[i]
#include <bits/stdc++.h> using namespace std; const int N=2e5+5; int n, h[N]; long long f[N], ans=0, w[N], s[N]; int lowbit(int x) { return x&(-x); } void add(int x, long long y) { for (int i=x; i<=n; i+=lowbit(i)) s[i]=max(s[i], y); } long long query(int x) { long long res=0; for (int i=x; i>=1; i-=lowbit(i)) res=max(s[i], res); return res; } int main() { scanf("%d", &n); for (int i=1; i<=n; i++) scanf("%d", &h[i]); for (int i=1; i<=n; i++) scanf("%lld", &w[i]); for (int i=1; i<=n; i++) { f[i]=max(w[i], w[i]+query(h[i]-1)); add(h[i], f[i]); } for (int i=1; i<=n; i++) ans=max(ans, f[i]); printf("%lld", ans); return 0; } /* 7 1 5 2 6 3 7 4 60 80 20 100 90 40 20 7 1 5 2 6 3 7 4 60 80 20 100 90 40 20 280 */