AcWing3662-最大上升子序列和(树状数组优化dp+离散化)
思路:
数据范围是\(1e5\).
先回想数据范围为\(1e3\)的做法:
\(dp[i]\)表示以第i个数为结尾的最大上升子序列和,转移就是\(dp[i]=max(dp[j]+w[i]),1<=j<i\)
时间复杂度\(O(n^{2})\)
这题显然过不去,考虑用数据结构优化。
每次转移过来的都是前缀的最大值,可以用树状数组维护,时间复杂度变为\(O(nlogn)\)
由于本题数据范围很大,还需要离散化。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
LL n,tr[N],a[N],dp[N];
vector<LL>nums;
LL lowbit(LL x)
{
return x & -x;
}
void update(LL x, LL c)
{
for (int i = x; i <= n; i += lowbit(i)) tr[i] = max(tr[i],c);
}
LL query(LL x)
{
LL res = 0;
for (int i = x; i; i -= lowbit(i)) res =max(res, tr[i]);
return res;
}
int main()
{
cin>>n;
for (int i = 1; i <= n; i ++ ){
cin>>a[i];
nums.push_back(a[i]);
}
sort(nums.begin(),nums.end());
nums.erase(unique(nums.begin(),nums.end()),nums.end());
LL res=0;
for (int i = 1; i <= n; i ++ ){
int t=lower_bound(nums.begin(),nums.end(),a[i])-nums.begin()+1;
///使下标从1开始
dp[i]=query(t-1)+a[i];
res=max(res,dp[i]);
update(t,dp[i]);
}
cout<<res<<endl;
return 0;
}