最大上升子序列和+树状数组维护区间最大值
给定一个长度为 nn 的整数序列 a1,a2,…,an。
请你选出一个该序列的严格上升子序列,要求所选子序列的各元素之和尽可能大。
请问这个最大值是多少?
输入格式
第一行包含整数 n。
第二行包含 n 个整数 a1,a2,…,an。
输出格式
输出最大的上升子序列和。
数据范围
对于前三个测试点,1≤n≤4。
对于全部测试点,1≤n≤1e5,1≤ai≤1e9。
输入样例1:
2
100 40
输出样例1:
100
输入样例2:
4
1 9 7 10
输出样例2:
20
样例解释
对于样例 11,我们只选取 100。
对于样例 22,我们选取 1,9,10。
首先呢我们先写一个暴力,然后在优化。
我们令 f[i] 指的是以i结尾的最长上升子序列和。
然后这个代码就是:
f[1]=a[1]; for(int i=2;i<=n;i++){ for(int j=1;j<=i;j++){ if(a[i]>a[j]){ f[i]=max(f[i],f[j]+a[i]); } } } int ans=0; for(int i=1;i<=n;i++){ ans=max(ans,f[i]); } cout<<ans<<endl;
这样写显然是T的,然后我们要想一个方法来优化他,显然我们需要求的是小于a[i]的的并且小于i的f值的最大值。这个显然线段树和树状数组是可以解决的,
重要的是我们需要离散化
然后这个代码就是:
#include<iostream> #include<algorithm> #include<set> #include<cstring> using namespace std; typedef long long ll; const int maxn=1e6+100; ll a[maxn],id[maxn],f[maxn]; ll c[maxn]; int cnt=0; ll lowbit(ll x){ return x&-x; } void add(int x,ll k){ for(int i=x;i<=cnt;i+=lowbit(i)){ c[i]=max(k,c[i]); } } ll ask(ll x){ ll ans=0; for(int i=x;i>0;i-=lowbit(i)){ ans=max(ans,c[i]); } return ans; } int get(int x){ return lower_bound(id+1,id+cnt+1,x)-id; } int main(){ int n; cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; id[i]=a[i]; } sort(id+1,id+n+1); cnt=unique(id+1,id+n+1)-id-1; for(int i=1;i<=n;i++){ int p=get(a[i]); f[i]=ask(p-1)+a[i]; add(p,f[i]); } ll ans=0; for(int i=1;i<=n;i++){ ans=max(ans,f[i]); } cout<<ans<<endl; return 0; }