给定一个长度为 nn 的整数序列 a1,a2,,ana1,a2,…,an。

请你选出一个该序列的严格上升子序列,要求所选子序列的各元素之和尽可能大。

请问这个最大值是多少?

输入格式

第一行包含整数 nn。

第二行包含 nn 个整数 a1,a2,,ana1,a2,…,an。

输出格式

输出最大的上升子序列和。

数据范围

对于前三个测试点,1n41≤n≤4。
对于全部测试点,1n105,1ai1091≤n≤105,1≤ai≤109。

输入样例1:

2
100 40

输出样例1:

100

输入样例2:

4
1 9 7 10

输出样例2:

20

样例解释

对于样例 11,我们只选取 100100。

对于样例 22,我们选取 1,9,101,9,10。

#include <algorithm>
#include <cstring>
#include <iostream>
#include <unordered_map>
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
LL n, a[N], b[N], sum[N], maxSum[N];
unordered_map<int, LL> mp;
LL c[N];
// 查询前缀和:查询序列 a 第 1~x 个数的和
//找出在x之前的元素的最大值
LL ask(LL x) {
    LL ans = 0;
    for (; x; x -= x & -x) ans = max(ans, c[x]);
    return ans;
}
// 单点增加:给序列中的一个数 a[x] 加上 y
// 算法:自下而上每个节点都要增加 y
void add(int x, LL y) {
    for (; x <= n; x += x & -x) c[x] = max(c[x], y);
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    memcpy(b, a, sizeof a);
    sort(b + 1, b + n + 1);
    LL m = 0;
    for (int i = 1; i <= n; i++) {
        if (!mp.count(b[i]))
            mp[b[i]] = ++m;
    }
    //相当于离散化
    for (int i = 1; i <= n; i++) {
        sum[i] =  ask(mp[a[i]] - 1) + a[i];
        add(mp[a[i]], sum[i]);
    }
    
    LL ans = 0;
    for (int i = 1; i <= n; i++) {
        ans = max(ans, sum[i]);
    }
    cout << ans << endl;
    return 0;
}