Link to this code: https://cses.fi/paste/c516942579b87620c52299/
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O3")
#define int long long 
const int N = 5e6 + 10, M = 22;
const int inf = 1e15 + 10;

template <typename num_t> 
struct segtree {
  int n, depth;
  vector<num_t> tree, lazy;

  void init(int s, long long* arr) {
    n = s;
    tree = vector<num_t>(4 * s, 0);
    lazy = vector<num_t>(4 * s, 0);
    init(0, 0, n - 1, arr);
  }

  num_t init(int i, int l, int r, long long* arr) {
    if (l == r) return tree[i] = arr[l];

    int mid = (l + r) / 2;
    num_t a = init(2 * i + 1, l, mid, arr),
          b = init(2 * i + 2, mid + 1, r, arr);
    return tree[i] = a.op(b);
  }

  void update(int l, int r, num_t v) {
	if (l > r) return;
    update(0, 0, n - 1, l, r, v);
  }

  num_t update(int i, int tl, int tr, int ql, int qr, num_t v) {
    eval_lazy(i, tl, tr);
	
	if (tr < ql || qr < tl) return tree[i];
    if (ql <= tl && tr <= qr) {
      lazy[i] = lazy[i].val + v.val;
      eval_lazy(i, tl, tr);
      return tree[i];
    }
    
    int mid = (tl + tr) / 2;
    num_t a = update(2 * i + 1, tl, mid, ql, qr, v),
          b = update(2 * i + 2, mid + 1, tr, ql, qr, v);
    return tree[i] = a.op(b);
  }

  num_t query(int l, int r) {
	if (l > r) return num_t::null_v;
    return query(0, 0, n-1, l, r);
  }

  num_t query(int i, int tl, int tr, int ql, int qr) {
    eval_lazy(i, tl, tr);
    
    if (ql <= tl && tr <= qr) return tree[i];
    if (tr < ql || qr < tl) return num_t::null_v;

    int mid = (tl + tr) / 2;
    num_t a = query(2 * i + 1, tl, mid, ql, qr),
          b = query(2 * i + 2, mid + 1, tr, ql, qr);
    return a.op(b);
  }

  void eval_lazy(int i, int l, int r) {
    tree[i] = tree[i].lazy_op(lazy[i], (r - l + 1));
    if (l != r) {
      lazy[i * 2 + 1] = lazy[i].val + lazy[i * 2 + 1].val;
      lazy[i * 2 + 2] = lazy[i].val + lazy[i * 2 + 2].val;
    }

    lazy[i] = num_t();
  }
};

struct max_t {
  long long val;
  static const long long null_v = -9223372036854775807LL;

  max_t(): val(0) {}
  max_t(long long v): val(v) {}

  max_t op(max_t& other) {
    return max_t(max(val, other.val));
  }
  
  max_t lazy_op(max_t& v, int size) {
    return max_t(val + v.val);
  }
};

inline void solve(){
    int n;
    cin >> n;

    vector<int> v(n);
    for(auto &x : v) cin >> x;

    vector<pair<int,int>> a;
    for(int i = 0;i < n;i += 1){
        a.push_back({v[i], i});
    }

    sort(a.begin(), a.end());

    vector<int> l(n), r(n);

    {
        stack<int> st;
        for(int i = 0;i < n;i += 1){
            while(!st.empty() && v[i] > v[st.top()]){
                st.pop();
            }
            l[i] = (st.empty() ? -1 : st.top());
            st.push(i);
        }
    }

    {
        stack<int> st;
        for(int i = n - 1;i >= 0;i -= 1){
            while(!st.empty() && v[i] > v[st.top()]){
                st.pop();
            }
            r[i] = (st.empty() ? n : st.top());
            st.push(i);
        }
    }

    // for(int i = 0;i < n;i += 1){
    //     cout << l[i] << ' ' << r[i] << '\n';
    // }
    
    vector<int> dp(n);

    segtree<max_t> sgt;
    sgt.init(n, dp.data());

    for(int i = 0;i < n;i += 1){
        int ind = a[i].second;
        int ll = l[ind], rr = r[ind];

        dp[ind] = sgt.query(ll + 1, rr - 1).val + 1;
        sgt.update(ind,ind, dp[ind]);
    }

    // for(auto &x : dp) cout << x << ' ';
    // cout << '\n';

    cout << *max_element(dp.begin(), dp.end());

    
    
}

int32_t main() {

    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t = 1;
    // cin >> t;

    while(t--){
        solve();
        cout << "\n";
    }
}