Problem:
E: LISum

問題

長さ $N$ の数列 $A$ が与えられる。
数列 $A$ の最長増加部分列のひとつを $B$ とするとき、$\sum B_i$ の最大値を求めよ。

数列 $A$ の最長増加部分列とは、すべての $i < j$ で $A_i < A_j$ を満たす部分列のうち、最長なものを示す。

制約

入力値は全て整数である。

$1 \leq N \leq 10^5$

$0 \leq A_i \leq 10^5$

入力形式

入力は以下の形式で与えられる。

$N$

$A_1 \dots A_N$

出力

数列 $A$ の最長増加部分列のひとつを $B$ とするとき、$\sum B_i$ の最大値を出力せよ。また、末尾に改行も出力せよ。

サンプル

サンプル入力 1

4
6 4 7 8

サンプル出力 1

21

最長増加部分列は $ (6, 7, 8)$ と $(4, 7, 8)$ である。よって最大値は $21$ である。

サンプル入力 2

3
1000 2 3

サンプル出力 2

5

最長増加部分列は $(2,3)$ のみである。

サンプル入力 3

7
17 17 13 4 20 12 15

サンプル出力 3

31

サンプル入力 4

7
19 16 14 9 4 20 2

サンプル出力 4

39

Solution in C++ (judge verdict: Accepted)

#include <climits>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const int INF = (1<<30)-1+(1<<30);

struct SegmentTree {
private:
  int n;
  vector< pair<long long,long long> > node;//min,max
public:
  SegmentTree(int sz){
    n = 1;
    while(n < sz) n *= 2;
    node.resize(2*n-1,pair<long long,long long>(0,0));
  }
  void update(int idx, pair<long long,long long> p){
    idx += n-1;
    node[idx] = max(node[idx],p);
    while(idx > 0){
      idx = (idx-1)/2;
      node[idx] = max(node[2*idx+1],node[2*idx+2]);
    }
  }
  
  pair<long long,long long> get_max(int a, int b, int k=0, int l=0, int r=-1){
    if(r < 0) r = n;
    if(r <= a or b <= l) return {0,0};
    if(a <= l and r <= b) return node[k];
    pair<long long, long long> vl = get_max(a,b,2*k+1,l,(l+r)/2);
    pair<long long, long long> vr = get_max(a,b,2*k+2,(l+r)/2,r);
    return max(vl,vr);
  }
};

int main(){
  int M = 1e5+10;
  SegmentTree st(M);
  int N;
  cin >> N;
  vector<int> A(N);
  for(int i = 0; i < N; ++i){
    //cerr << i << " : " ;
    cin >> A[i];
    //cerr << A[i] << endl;
    pair<long long,long long> r = st.get_max(0,A[i]);
    //cerr << "get_max" << endl;
    ++r.first;
    r.second += A[i];
    st.update(A[i],r);
    //cerr << "update" << endl;
  }
  cout << st.get_max(0,M).second << endl;
  return 0;
}