AcWing3662-最大上升子序列和(树状数组优化dp+离散化)

link

思路:

数据范围是\(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;
}

posted @ 2021-06-13 19:28  OvO1  阅读(68)  评论(0编辑  收藏  举报