Problem:
Wireless Communication Network
We are setting up a wireless communication network in a mountain range. Communication
stations are to be located on the summits. The summits are on a straight line and have different
altitudes.
To minimize the cost, our communication network should have a tree structure, which is a
connected graph with the least number of edges. The structure of the network, that is, which
stations to communicate with which other stations, should be decided in advance.
We construct the communication network as follows.
Initially, each station forms a tree consisting of only that station.
In each step, we merge two trees that are adjacent by making a link between two stations
    in different trees. Two trees are called
adjacent
when all the summits in between a summit
    in one tree and a summit in the other belong to one of these two trees. Stations to link
    are those on the highest summits of the two trees; they are uniquely determined because
    the altitudes of the summits are distinct.
Repeat the step 2 until all the stations are connected, directly or indirectly.
Figure D.1. The tree formation for Sample 1
When a station detects an emergency event, an alert message should be broadcast to all the
stations. On receiving a message, each station relays the message to all the stations with direct
links, except for one from which it has come. The diameter of the network, that is, how many
hops are sufficient to distribute messages initiated at any stations, depends on the choice of the
two trees in the step 2 above.
To estimate the worst case delay of broadcast, we want to find the largest diameter of the
network possibly constructed by the above procedure.
Input
The input consists of a single test case of the following format.
$n$
${h_1}$
:
${h_n}$
Here, $n$ is the number of communication stations ($3 \leq n \leq 10^6$), and hi is an integer representing
the altitude of the $i$-th station ($1 \leq h_i \leq n$). The altitudes of the stations are distinct, that is,
$h_i \neq h_j$ if $i \neq j$.
Output
Output in a line a single integer representing the largest possible diameter of the tree.
Sample Input 1
8
1
8
2
3
5
4
6
7
Sample Output 1
6
Sample Input 2
4
1
2
3
4
Sample Output 2
3

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = int;
using PLL = pair<ll, ll>;
#define rep(i, n) for (ll i = 0; i < n; ++i)
constexpr ll INF = 2002002002;

template <typename T>
class segtree
{
public:
    T E;                              // const を外した
    vector<T> _data;
    function<T(T, T)> _query;         // const を外した
    int _length;                      // const を外した

    T _query_sub(int a, int b, int k, int l, int r) const {
        if (r <= a || b <= l) {
            return E;
        } else if (a <= l && r <= b) {
            return _data[k];
        } else {
            T vl = _query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = _query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return _query(vl, vr);
        }
    }

    segtree() {}
    segtree(int len, T e, function<T(T, T)> query)
        : E(e), _query(std::move(query)), _length(1)
    {
        while (_length < len) {
            _length <<= 1;
        }
        _data.assign(_length * 2 - 1, E);
    }

    // ★★★ コピー代入演算子 ★★★
    segtree& operator=(const segtree& other) {
        if (this == &other) return *this;

        this->E = other.E;
        this->_query = other._query;
        this->_length = other._length;
        this->_data = other._data;

        return *this;
    }

    // ★★★ ムーブ代入演算子（任意） ★★★
    segtree& operator=(segtree&& other) noexcept {
        if (this == &other) return *this;

        this->E = std::move(other.E);
        this->_query = std::move(other._query);
        this->_length = other._length;
        this->_data = std::move(other._data);

        return *this;
    }

    size_t size() const { return _length; }

    T& operator[](size_t i) {
        if (i < 0 || i >= _length) {
            while (true) {}
        }
        return _data[i + _length - 1];
    }

    void build() {
        for (int i = _length - 2; i >= 0; --i) {
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    void update(int i, T value) {
        if (i < 0 || i >= _length) {
            while (true) {}
        }
        i += _length - 1;
        _data[i] = value;
        while (i > 0) {
            i = (i - 1) >> 1;
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    T query(int a, int b) const {
        if (a < 0 || b < 0 || a >= _length || b > _length) {
            while (true) {}
        }
        return _query_sub(a, b, 0, 0, _length);
    }

    static segtree<T> RangeMaximumQuery(int len, T e = numeric_limits<T>::min()) {
        return segtree<T>(len, e, [](T a, T b) { return max(a, b); });
    }
};

// segtree<PLL> seg;
// int ans = 0;
// int dfs(int l, int r, int depth) {
//     if (r - l == 1) {
//         ans = max(ans, depth);
//         return 1;
//     }
//     if (r <= l) {
//         return 0;
//     }
//     // 最大を取得
//     int i = seg.query(l, r).second;

//     // 左
//     int left = dfs(l, i, depth + 1);
//     int right = dfs(i + 1, r, depth + 1);

//     ans = max(ans, left + right + depth);
//     return max(left, right) + 1;
// }

int main() {
    ll n; cin >> n;
    vector<ll> h(n);
    rep(i, n) {
        cin >> h[i];
    }

    segtree<PLL> seg = segtree<PLL>(n, {-INF, -INF}, [](PLL a, PLL b) { return max(a, b); });
    rep(i, n) {
        seg[i] = {h[i], i};
    }
    seg.build();

    ll ans = 0;
    auto dfs = [&](auto dfs, ll l, ll r, ll depth) -> ll {
        if (r - l == 1) {
            ans = max(ans, depth);
            return 1;
        }
        if (r <= l) {
            return 0;
        }
        // 最大を取得
        ll i = seg.query(l, r).second;

        // 左
        ll left = dfs(dfs, l, i, depth + 1);
        ll right = dfs(dfs, i + 1, r, depth + 1);

        ans = max(ans, left + right + depth);
        return max(left, right) + 1;
    };
    dfs(dfs, 0, n, 0);
    // dfs(0, n, 0);

    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 300
memory_kb: 132952
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using PLL = pair<ll, ll>;
#define rep(i, n) for (ll i = 0; i < n; ++i)
constexpr ll INF = 9009009009009009009LL;

template <typename T>
class segtree
{
public:
    T E;                              // const を外した
    vector<T> _data;
    function<T(T, T)> _query;         // const を外した
    int _length;                      // const を外した

    T _query_sub(int a, int b, int k, int l, int r) const {
        if (r <= a || b <= l) {
            return E;
        } else if (a <= l && r <= b) {
            return _data[k];
        } else {
            T vl = _query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = _query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return _query(vl, vr);
        }
    }

    segtree() {}
    segtree(int len, T e, function<T(T, T)> query)
        : E(e), _query(std::move(query)), _length(1)
    {
        while (_length < len) {
            _length <<= 1;
        }
        _data.assign(_length * 2 - 1, E);
    }

    // ★★★ コピー代入演算子 ★★★
    segtree& operator=(const segtree& other) {
        if (this == &other) return *this;

        this->E = other.E;
        this->_query = other._query;
        this->_length = other._length;
        this->_data = other._data;

        return *this;
    }

    // ★★★ ムーブ代入演算子（任意） ★★★
    segtree& operator=(segtree&& other) noexcept {
        if (this == &other) return *this;

        this->E = std::move(other.E);
        this->_query = std::move(other._query);
        this->_length = other._length;
        this->_data = std::move(other._data);

        return *this;
    }

    size_t size() const { return _length; }

    T& operator[](size_t i) {
        if (i < 0 || i >= _length) {
            while (true) {}
        }
        return _data[i + _length - 1];
    }

    void build() {
        for (int i = _length - 2; i >= 0; --i) {
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    void update(int i, T value) {
        if (i < 0 || i >= _length) {
            while (true) {}
        }
        i += _length - 1;
        _data[i] = value;
        while (i > 0) {
            i = (i - 1) >> 1;
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    T query(int a, int b) const {
        if (a < 0 || b < 0 || a >= _length || b > _length) {
            while (true) {}
        }
        return _query_sub(a, b, 0, 0, _length);
    }

    static segtree<T> RangeMaximumQuery(int len, T e = numeric_limits<T>::min()) {
        return segtree<T>(len, e, [](T a, T b) { return max(a, b); });
    }
};

segtree<PLL> seg;
int ans = 0;
int dfs(int l, int r, int depth) {
    if (r - l == 1) {
        ans = max(ans, depth);
        return 1;
    }
    if (r <= l) {
        return 0;
    }
    // 最大を取得
    int i = seg.query(l, r).second;

    // 左
    int left = dfs(l, i, depth + 1);
    int right = dfs(i + 1, r, depth + 1);

    ans = max(ans, left + right + depth);
    return max(left, right) + 1;
}

int main() {
    ll n; cin >> n;
    vector<ll> h(n);
    rep(i, n) {
        cin >> h[i];
    }

    seg = segtree<PLL>(n, {-INF, -INF}, [](PLL a, PLL b) { return max(a, b); });
    rep(i, n) {
        seg[i] = {h[i], i};
    }
    seg.build();

    
    // auto dfs = [&](auto dfs, ll l, ll r, ll depth) -> ll {
    //     cout << l << " " << r << " " << depth << endl;
    //     if (r - l == 1) {
    //         ans = max(ans, depth);
    //         return 1;
    //     }
    //     if (r <= l) {
    //         return 0;
    //     }
    //     // 最大を取得
    //     ll i = seg.query(l, r).second;

    //     // 左
    //     ll left = dfs(dfs, l, i, depth + 1);
    //     ll right = dfs(dfs, i + 1, r, depth + 1);

    //     ans = max(ans, left + right + depth);
    //     return max(left, right) + 1;
    // };
    // dfs(dfs, 0, n, 0);
    dfs(0, n, 0);

    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 310
memory_kb: 153312
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using PLL = pair<ll, ll>;
#define rep(i, n) for (ll i = 0; i < n; ++i)
constexpr ll INF = 9009009009009009009LL;

template <typename T>
class segtree
{
    protected:
    const T E;
    vector<T> _data;
    const function<T(T, T)> _query;
    int _length;

    T _query_sub(int a, int b, int k, int l, int r) const {
        if(r <= a || b <= l) {
            return E;
        }
        else if (a <= l && r <= b) {
            return _data[k];
        }
        else {
            T vl = _query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = _query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return _query(vl, vr);
        }
    }

    public:
    segtree(int len, T e, function<T(T, T)> query) : E(e), _query(std::move(query)), _length(1) {
        while (_length < len) {
            _length <<= 1;
        }
        _data.assign(_length * 2 - 1, E);
    }
    
    size_t size() const { return _length; }

    T &operator[](size_t i) {
        if (i < 0 || i >= _length) {
            while (true) {}
        }
        return _data[i + _length - 1];
    }

    void build() {
        for(int i = _length - 2; i >= 0; --i) {
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    void update(int i, T value) {
        if (i < 0 || i >= _length) {
            while (true) {}
        }
        i += _length - 1;
        _data[i] = value;
        while (i > 0) {
            i = (i - 1) >> 1;
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    T query(int a, int b) const {
        if (a < 0 || b < 0 || a >= _length || b > _length) 
        {
            while (true) {}
        }
        return _query_sub(a, b, 0, 0, _length);
    }

    static segtree<T> RangeMaximumQuery(int len, T e = numeric_limits<T>::min()) {
        return segtree<T>(len, e, [](T a, T b) { return max(a, b); });
    }
};

int main() {
    ll n; cin >> n;
    vector<ll> h(n);
    rep(i, n) {
        cin >> h[i];
    }

    segtree<PLL> seg = segtree<PLL>::RangeMaximumQuery(n);
    rep(i, n) {
        seg[i] = {h[i], i};
    }
    seg.build();

    ll ans = 0;
    map<pair<ll, PLL>, ll> mp;
    auto dfs = [&](auto dfs, ll l, ll r, ll depth) -> ll {
        if (mp.count({depth, {l, r}})) return mp[{depth, {l, r}}];
        if (r - l == 1) {
            ans = max(ans, depth);
            return 1;
        }
        if (r <= l) {
            return 0;
        }
        // 最大を取得
        ll i = seg.query(l, r).second;

        // 左
        ll left = dfs(dfs, l, i, depth + 1);
        ll right = dfs(dfs, i + 1, r, depth + 1);

        ans = max(ans, left + right + depth);
        return mp[{depth, {l, r}}] = max(left, right) + 1;
    };
    dfs(dfs, 0, n, 0);

    cout << ans << endl;
    return 0;
}
accuracy: 0.04294478527607362
time_ms: 430
memory_kb: 96096
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using PLL = pair<ll, ll>;
#define rep(i, n) for (ll i = 0; i < n; ++i)
constexpr ll INF = 9009009009009009009LL;

template <typename T>
class segtree
{
    protected:
    const T E;
    vector<T> _data;
    const function<T(T, T)> _query;
    int _length;

    T _query_sub(int a, int b, int k, int l, int r) const {
        if(r <= a || b <= l) {
            return E;
        }
        else if (a <= l && r <= b) {
            return _data[k];
        }
        else {
            T vl = _query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = _query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return _query(vl, vr);
        }
    }

    public:
    segtree(int len, T e, function<T(T, T)> query) : E(e), _query(std::move(query)), _length(1) {
        while (_length < len) {
            _length <<= 1;
        }
        _data.assign(_length * 2 - 1, E);
    }
    
    size_t size() const { return _length; }

    T &operator[](size_t i) {
        if (i < 0 || i >= _length) {
            while (true) {}
        }
        return _data[i + _length - 1];
    }

    void build() {
        for(int i = _length - 2; i >= 0; --i) {
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    void update(int i, T value) {
        if (i < 0 || i >= _length) {
            while (true) {}
        }
        i += _length - 1;
        _data[i] = value;
        while (i > 0) {
            i = (i - 1) >> 1;
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    T query(int a, int b) const {
        if (a < 0 || b < 0 || a >= _length || b > _length) 
        {
            while (true) {}
        }
        return _query_sub(a, b, 0, 0, _length);
    }

    static segtree<T> RangeMaximumQuery(int len, T e = numeric_limits<T>::min()) {
        return segtree<T>(len, e, [](T a, T b) { return max(a, b); });
    }
};

int main() {
    ll n; cin >> n;
    vector<ll> h(n);
    rep(i, n) {
        cin >> h[i];
    }

    segtree<PLL> seg = segtree<PLL>::RangeMaximumQuery(n);
    rep(i, n) {
        seg[i] = {h[i], i};
    }
    seg.build();

    ll ans = 0;
    auto dfs = [&](auto dfs, ll l, ll r, ll depth) -> ll {
        if (r - l == 1) {
            ans = max(ans, depth);
            return 1;
        }
        if (r <= l) {
            return 0;
        }
        // 最大を取得
        ll i = seg.query(l, r).second;

        // 左
        ll left = dfs(dfs, l, i, depth + 1);
        ll right = dfs(dfs, i + 1, r, depth + 1);

        ans = max(ans, left + right + depth);
        return max(left, right) + 1;
    };
    dfs(dfs, 0, n, 0);

    cout << ans << endl;
    return 0;
}
accuracy: 0.04294478527607362
time_ms: 210
memory_kb: 43872
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using PLL = pair<ll, ll>;
#define rep(i, n) for (ll i = 0; i < n; ++i)
constexpr ll INF = 9009009009009009009LL;

template <typename T>
class segtree
{
    protected:
    const T E;
    vector<T> _data;
    const function<T(T, T)> _query;
    int _length;

    T _query_sub(int a, int b, int k, int l, int r) const {
        if(r <= a || b <= l) {
            return E;
        }
        else if (a <= l && r <= b) {
            return _data[k];
        }
        else {
            T vl = _query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = _query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return _query(vl, vr);
        }
    }

    public:
    segtree(int len, T e, function<T(T, T)> query) : E(e), _query(std::move(query)), _length(1) {
        while (_length < len) {
            _length <<= 1;
        }
        _data.assign(_length * 2 - 1, E);
    }
    
    size_t size() const { return _length; }

    T &operator[](size_t i) {
        if (i < 0 || i >= _length) throw out_of_range("Index out of range");
        return _data[i + _length - 1];
    }

    void build() {
        for(int i = _length - 2; i >= 0; --i) {
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    void update(int i, T value) {
        if (i < 0 || i >= _length) throw out_of_range("Index out of range");
        i += _length - 1;
        _data[i] = value;
        while (i > 0) {
            i = (i - 1) >> 1;
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    T query(int a, int b) const {
        if (a < 0 || b < 0 || a >= _length || b > _length) throw out_of_range("Index out of range");
        return _query_sub(a, b, 0, 0, _length);
    }

    static segtree<T> RangeMaximumQuery(int len, T e = numeric_limits<T>::min()) {
        return segtree<T>(len, e, [](T a, T b) { return max(a, b); });
    }
};

int main() {
    ll n; cin >> n;
    vector<ll> h(n);
    rep(i, n) {
        cin >> h[i];
    }

    segtree<PLL> seg = segtree<PLL>::RangeMaximumQuery(n);
    rep(i, n) {
        seg[i] = {h[i], i};
    }
    seg.build();

    ll ans = 0;
    auto dfs = [&](auto dfs, ll l, ll r, ll depth) -> ll {
        if (r - l == 1) {
            ans = max(ans, depth);
            return 1;
        }
        if (r <= l) {
            return 0;
        }
        // 最大を取得
        ll i = seg.query(l, r).second;

        // 左
        ll left = dfs(dfs, l, i, depth + 1);
        ll right = dfs(dfs, i + 1, r, depth + 1);

        ans = max(ans, left + right + depth);
        return max(left, right) + 1;
    };
    dfs(dfs, 0, n, 0);

    cout << ans << endl;
    return 0;
}
accuracy: 0.04294478527607362
time_ms: 210
memory_kb: 44000
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vl = vector<ll>;
using PLL = pair<ll, ll>;
#define rep(i, n) for (ll i = 0; i < n; ++i)
constexpr ll INF = 9009009009009009009LL;

template <typename T>
class segtree
{
    protected:
    const T E;
    vector<T> _data;
    const function<T(T, T)> _query;
    int _length;

    T _query_sub(int a, int b, int k, int l, int r) const {
        if(r <= a || b <= l) {
            return E;
        }
        else if (a <= l && r <= b) {
            return _data[k];
        }
        else {
            T vl = _query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = _query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return _query(vl, vr);
        }
    }

    public:
    segtree(int len, T e, function<T(T, T)> query) : E(e), _query(std::move(query)), _length(1) {
        while (_length < len) {
            _length <<= 1;
        }
        _data.assign(_length * 2 - 1, E);
    }
    
    size_t size() const { return _length; }

    T &operator[](size_t i) {
        if (i < 0 || i >= _length) throw out_of_range("Index out of range");
        return _data[i + _length - 1];
    }

    void build() {
        for(int i = _length - 2; i >= 0; --i) {
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    void update(int i, T value) {
        if (i < 0 || i >= _length) throw out_of_range("Index out of range");
        i += _length - 1;
        _data[i] = value;
        while (i > 0) {
            i = (i - 1) >> 1;
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    T query(int a, int b) const {
        if (a < 0 || b < 0 || a >= _length || b > _length) throw out_of_range("Index out of range");
        return _query_sub(a, b, 0, 0, _length);
    }

    static segtree<T> RangeMaximumQuery(int len, T e = numeric_limits<T>::min()) {
        return segtree<T>(len, e, [](T a, T b) { return max(a, b); });
    }
};

ll get_lis(vl a) {
    ll ans = 0;
    vl dp(a.size() + 1, INF);
    dp[0] = -INF;
    rep(i, a.size()) {
        auto it = upper_bound(dp.begin(), dp.end(), a[i]);
        *it = a[i];
        ans = max(ans, (ll)(it - dp.begin()));
    }
    return ans;
}

int main() {
    ll n; cin >> n;
    vector<ll> h(n);
    rep(i, n) {
        cin >> h[i];
    }

    segtree<PLL> seg = segtree<PLL>::RangeMaximumQuery(n);
    rep(i, n) {
        seg[i] = {h[i], i};
    }
    seg.build();

    ll ans = 0;
    auto dfs = [&](auto dfs, ll l, ll r, ll depth) -> ll {
        if (r - l == 1) {
            ans = max(ans, depth);
            return 1;
        }
        if (r <= l) {
            return 0;
        }
        // 最大を取得
        ll i = seg.query(l, r).second;

        // 左
        ll left = dfs(dfs, l, i, depth + 1);
        ll right = dfs(dfs, i + 1, r, depth + 1);

        ans = max(ans, left + right + depth);
        return max(left, right) + 1;
    };
    dfs(dfs, 0, n, 0);

    cout << ans << endl;
    return 0;
}
accuracy: 0.04294478527607362
time_ms: 210
memory_kb: 44000
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vl = vector<ll>;
using PLL = pair<ll, ll>;
#define rep(i, n) for (ll i = 0; i < n; ++i)
constexpr ll INF = 9009009009009009009LL;

template <typename T>
class segtree
{
    protected:
    const T E;
    vector<T> _data;
    const function<T(T, T)> _query;
    int _length;

    T _query_sub(int a, int b, int k, int l, int r) const {
        if(r <= a || b <= l) {
            return E;
        }
        else if (a <= l && r <= b) {
            return _data[k];
        }
        else {
            T vl = _query_sub(a, b, k * 2 + 1, l, (l + r) / 2);
            T vr = _query_sub(a, b, k * 2 + 2, (l + r) / 2, r);
            return _query(vl, vr);
        }
    }

    public:
    segtree(int len, T e, function<T(T, T)> query) : E(e), _query(std::move(query)), _length(1) {
        while (_length < len) {
            _length <<= 1;
        }
        _data.assign(_length * 2 - 1, E);
    }
    
    size_t size() const { return _length; }

    T &operator[](size_t i) {
        if (i < 0 || i >= _length) throw out_of_range("Index out of range");
        return _data[i + _length - 1];
    }

    void build() {
        for(int i = _length - 2; i >= 0; --i) {
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    void update(int i, T value) {
        if (i < 0 || i >= _length) throw out_of_range("Index out of range");
        i += _length - 1;
        _data[i] = value;
        while (i > 0) {
            i = (i - 1) >> 1;
            _data[i] = _query(_data[i * 2 + 1], _data[i * 2 + 2]);
        }
    }

    T query(int a, int b) const {
        if (a < 0 || b < 0 || a >= _length || b > _length) throw out_of_range("Index out of range");
        return _query_sub(a, b, 0, 0, _length);
    }

    static segtree<T> RangeMaximumQuery(int len, T e = numeric_limits<T>::min()) {
        return segtree<T>(len, e, [](T a, T b) { return max(a, b); });
    }
};

ll get_lis(vl a) {
    ll ans = 0;
    vl dp(a.size() + 1, INF);
    dp[0] = -INF;
    rep(i, a.size()) {
        auto it = upper_bound(dp.begin(), dp.end(), a[i]);
        *it = a[i];
        ans = max(ans, (ll)(it - dp.begin()));
    }
    return ans;
}

int main() {
    ll n; cin >> n;
    vector<ll> h(n);
    rep(i, n) {
        cin >> h[i];
    }

    segtree<PLL> seg = segtree<PLL>::RangeMaximumQuery(n);
    rep(i, n) {
        seg[i] = {h[i], i};
    }
    seg.build();

    ll ans = 0;
    auto dfs = [&](auto dfs, ll l, ll r, ll depth) -> ll {
        if (r - l == 1) {
            ans = max(ans, depth);
            return 1;
        }
        if (r == l) {
            return 0;
        }
        // 最大を取得
        ll i = seg.query(l, r).second;

        // 左
        ll left = dfs(dfs, l, i, depth + 1);
        ll right = dfs(dfs, i + 1, r, depth + 1);

        ans = max(ans, left + right + depth);
        return max(left, right) + 1;
    };
    dfs(dfs, 0, n, 0);

    cout << ans << endl;
    return 0;
}
accuracy: 0.04294478527607362
time_ms: 220
memory_kb: 44000
final_rank: 18

code_snippet: // #define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1LL << 60;
#define rep(i, a) for(ll i = 0; i < (a); i++)
#define all(a) begin(a), end(a)
// #define sz(a) (a).size()
bool chmin(auto& a, auto b) { return a > b ? a = b, 1 : 0; }
bool chmax(auto& a, auto b) { return a < b ? a = b, 1 : 0; }
#define out(a) cout << (a) << endl
using vll = vector<ll>;
using vvll = vector<vll>;

template<class T>
tuple<vll, vll, vll, ll> cartesian_tree(const vector<T>& v, bool b=false) {
  ll n = v.size();
  vll p(n, -1);
  vll l(n, -1);
  vll r(n, -1);
  int top = 0;
  for(int i=1;i<n;i++) {
    p[i] = i-1;
    r[i-1] = i;
    while(p[i] >= 0 && ((v[i] > v[p[i]]) == b)) {
      ll j = p[i];
      p[i] = p[p[i]];
      if(p[i] >= 0) r[p[i]] = i;
      r[j] = l[i];
      if(r[j] >= 0) p[r[j]] = j;
      p[j] = i;
      l[i] = j;
    }
    if(p[i] == -1) top = i;
  }
  return {p,l,r,top};
}

ll solve(ll n, vll h)
{
  for(auto &e : h) e = -e;
  auto [p,l,r,root] = cartesian_tree(h);
  ll ans = 0;
  function<ll(ll,ll)> dfs = [&](ll v, ll d){
    ll ret = 0;
    ll lx = 0, rx = 0;
    if(l[v] != -1) lx = dfs(l[v],d+1);
    if(r[v] != -1) rx = dfs(r[v],d+1);
    // cout << h[v] << " " << d << endl;
    // cout << lx << " " << rx << " " << lx + rx + d << endl;
    chmax(ans,lx+rx+d);
    return max(lx,rx)+1;
  };
  dfs(root,0);
  return ans;
}

ll solve_naive(ll n, vll h)
{
  rep(i, n) h[i]--;
  auto calc_dist = [&](vvll &tree, ll st)
  {
    vll ret(tree.size(), INF);
    ret[st] = 0;
    function<void(ll, ll)> dfs = [&](ll v, ll p)
    {
      for(auto e : tree[v])
      {
        if(e == p) continue;
        ret[e] = ret[v] + 1;
        dfs(e, v);
      }
    };
    dfs(st, -1);
    return ret;
  };
  auto calc_diam = [&](vvll &tree)
  {
    auto d1 = calc_dist(tree, 0);
    ll l = distance(d1.begin(), max_element(all(d1)));
    auto d2 = calc_dist(tree, l);
    return *max_element(all(d2));
  };
  ll ans = 0;
  set<pair<vll, vvll>> reached;
  function<void(vll, vvll)> dfs = [&](vll rngs, vvll tree)
  {
    if(reached.count(make_pair(rngs, tree))) return;
    reached.insert(make_pair(rngs, tree));
    // for(auto e : rngs) cout << e << " ";
    // cout << endl;
    // rep(i, n)
    // {
    //   cout << i << ": ";
    //   for(auto e : tree[i]) cout << e << " ";
    //   cout << endl;
    // }
    if(rngs.size() == 1)
    {
      chmax(ans, calc_diam(tree));
      return;
    }
    rep(i, rngs.size() - 1)
    {
      vvll ntree = tree;
      ll a = rngs[i], b = rngs[i + 1];
      vll nrngs(rngs.begin(), rngs.begin() + i);
      nrngs.push_back(max(a, b));
      nrngs.insert(nrngs.end(), rngs.begin() + i + 2, rngs.end());
      ntree[a].push_back(b);
      ntree[b].push_back(a);
      dfs(nrngs, ntree);
    }
  };
  dfs(h, vvll(n));
  return ans;
}

random_device seed;
mt19937_64 mt(seed());

void test()
{
  ll n = uniform_int_distribution<ll>(4, 7)(mt);
  vll h(n);
  iota(all(h), 1);
  shuffle(all(h), mt);
  ll found = solve(n, h);
  ll expect = solve_naive(n, h);
  if(found != expect)
  {
    cerr << n << endl;
    rep(i, n) cerr << h[i] << " ";
    cerr << endl;
    cerr << "found: " << found << endl;
    cerr << "expect " << expect << endl;
    assert(false);
  }
}

int main() {
  ll n; cin >> n;
  vll h(n);
  rep(i,n) cin >> h[i];
  out(solve(n, h));
  // while(true)
  // {
  //   test();
  // }
}
accuracy: 1
time_ms: 150
memory_kb: 120560
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define vi vector<int>
#define vl vector<ll>
#define vii vector<pair<int,int>>
#define vll vector<pair<ll,ll>>
#define vvi vector<vector<int>>
#define vvl vector<vector<ll>>
#define vvii vector<vector<pair<int,int>>>
#define vvll vector<vector<pair<ll,ll>>>
#define vst vector<string>
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define mkunique(x) sort(all(x));(x).erase(unique(all(x)),(x).end())
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=1000005,INF=15<<26;

// BIT セグ木 遅延セグ木 のみ

// from: https://gist.github.com/yosupo06/ddd51afb727600fd95d9d8ad6c3c80c9
// (based on AtCoder STL)

#include <algorithm>
#include <array>
#ifdef _MSC_VER
#include <intrin.h>
#endif
namespace atcoder {
namespace internal {
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}
}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
typename std::conditional<std::is_same<T, __int128_t>::value ||
std::is_same<T, __int128>::value,
std::true_type,
std::false_type>::type;

template <class T>
using is_unsigned_int128 =
typename std::conditional<std::is_same<T, __uint128_t>::value ||
std::is_same<T, unsigned __int128>::value,
std::true_type,
std::false_type>::type;

template <class T>
using make_unsigned_int128 =
typename std::conditional<std::is_same<T, __int128_t>::value,
__uint128_t,
unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
is_signed_int128<T>::value ||
is_unsigned_int128<T>::value,
std::true_type,
std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
is_signed_int128<T>::value,
std::true_type,
std::false_type>::type;

template <class T>
using is_unsigned_int =
typename std::conditional<(is_integral<T>::value &&
                           std::is_unsigned<T>::value) ||
is_unsigned_int128<T>::value,
std::true_type,
std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
is_signed_int128<T>::value,
make_unsigned_int128<T>,
typename std::conditional<std::is_signed<T>::value,
std::make_unsigned<T>,
std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
std::true_type,
std::false_type>::type;

template <class T>
using is_unsigned_int =
typename std::conditional<is_integral<T>::value &&
std::is_unsigned<T>::value,
std::true_type,
std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
std::make_unsigned<T>,
std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <vector>

namespace atcoder {

template <class T> struct fenwick_tree {
    using U = internal::to_unsigned_t<T>;
    
public:
    fenwick_tree() : _n(0) {}
    fenwick_tree(int n) : _n(n), data(n) {}
    
    void add(int p, T x) {
        assert(0 <= p && p < _n);
        p++;
        while (p <= _n) {
            data[p - 1] += U(x);
            p += p & -p;
        }
    }
    
    T sum(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        return sum(r) - sum(l);
    }
    
private:
    int _n;
    std::vector<U> data;
    
    U sum(int r) {
        U s = 0;
        while (r > 0) {
            s += data[r - 1];
            r -= r & -r;
        }
        return s;
    }
};

}  // namespace atcoder


#include <algorithm>
#include <cassert>
#include <iostream>
#include <vector>
namespace atcoder {

template <class S,
S (*op)(S, S),
S (*e)(),
class F,
S (*mapping)(F, S),
F (*composition)(F, F),
F (*id)()>
struct lazy_segtree {
public:
    lazy_segtree() : lazy_segtree(0) {}
    lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
    lazy_segtree(const std::vector<S>& v) : _n(int(v.size())) {
        log = internal::ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        lz = std::vector<F>(size, id());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }
    
    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    
    S get(int p) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        return d[p];
    }
    
    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return e();
        
        l += size;
        r += size;
        
        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push(r >> i);
        }
        
        S sml = e(), smr = e();
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        
        return op(sml, smr);
    }
    
    S all_prod() { return d[1]; }
    
    void apply(int p, F f) {
        assert(0 <= p && p < _n);
        p += size;
        for (int i = log; i >= 1; i--) push(p >> i);
        d[p] = mapping(f, d[p]);
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    void apply(int l, int r, F f) {
        assert(0 <= l && l <= r && r <= _n);
        if (l == r) return;
        
        l += size;
        r += size;
        
        for (int i = log; i >= 1; i--) {
            if (((l >> i) << i) != l) push(l >> i);
            if (((r >> i) << i) != r) push((r - 1) >> i);
        }
        
        {
            int l2 = l, r2 = r;
            while (l < r) {
                if (l & 1) all_apply(l++, f);
                if (r & 1) all_apply(--r, f);
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }
        
        for (int i = 1; i <= log; i++) {
            if (((l >> i) << i) != l) update(l >> i);
            if (((r >> i) << i) != r) update((r - 1) >> i);
        }
    }
    
    template <bool (*g)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return g(x); });
    }
    template <class G> int max_right(int l, G g) {
        assert(0 <= l && l <= _n);
        assert(g(e()));
        if (l == _n) return _n;
        l += size;
        for (int i = log; i >= 1; i--) push(l >> i);
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!g(op(sm, d[l]))) {
                while (l < size) {
                    push(l);
                    l = (2 * l);
                    if (g(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }
    
    template <bool (*g)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return g(x); });
    }
    template <class G> int min_left(int r, G g) {
        assert(0 <= r && r <= _n);
        assert(g(e()));
        if (r == 0) return 0;
        r += size;
        for (int i = log; i >= 1; i--) push((r - 1) >> i);
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!g(op(d[r], sm))) {
                while (r < size) {
                    push(r);
                    r = (2 * r + 1);
                    if (g(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }
    
private:
    int _n, size, log;
    std::vector<S> d;
    std::vector<F> lz;
    
    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
    void all_apply(int k, F f) {
        d[k] = mapping(f, d[k]);
        if (k < size) lz[k] = composition(f, lz[k]);
    }
    void push(int k) {
        all_apply(2 * k, lz[k]);
        all_apply(2 * k + 1, lz[k]);
        lz[k] = id();
    }
};

}  // namespace atcoder

#include <algorithm>
#include <cassert>
#include <vector>

namespace atcoder {

template <class S, S (*op)(S, S), S (*e)()> struct segtree {
public:
    segtree() : segtree(0) {}
    segtree(int n) : segtree(std::vector<S>(n, e())) {}
    segtree(const std::vector<S>& v) : _n(int(v.size())) {
        log = internal::ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }
    
    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }
    
    S get(int p) {
        assert(0 <= p && p < _n);
        return d[p + size];
    }
    
    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;
        
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }
    
    S all_prod() { return d[1]; }
    
    template <bool (*f)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }
    
    template <bool (*f)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }
    
private:
    int _n, size, log;
    std::vector<S> d;
    
    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};

}  // namespace atcoder

using T=pair<int,int>;

T f(T a,T b){
    return max(a,b);
}

T ti(){
    return mp(-1,-1);
}

atcoder::segtree<T,f,ti> seg;

pii solve(int l,int r){
    if(l==r) return mp(-INF,-INF);
    if(l+1==r){
        return mp(0,0);
    }
    auto [h,m]=seg.prod(l,r);
    auto a=solve(l,m),b=solve(m+1,r);
    
    int x=max({a.fi+1,b.fi+1,a.se+b.se+2});
    int y=max({a.se,b.se})+1;
    return mp(x,y);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N;cin>>N;
    vector<T> def(N);
    for(int i=0;i<N;i++){
        int x;cin>>x;
        def[i]=mp(x,i);
    }
    seg=atcoder::segtree<T,f,ti>(def);
    auto [a,b]=solve(0,N);
    cout<<a<<"\n";
}
accuracy: 1
time_ms: 130
memory_kb: 89496
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi vector<int>
#define vl vector<ll>
#define ov4(a, b, c, d, name, ...) name
#define rep3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep2(i, a, b) rep3(i, a, b, 1)
#define rep1(i, n) rep2(i, 0, n)
#define rep0(n) rep1(aaaaa, n)
#define rep(...) ov4(__VA_ARGS__, rep3, rep2, rep1, rep0)(__VA_ARGS__)
#define per(i, a, b) for(ll i = (a)-1; i >= (b); i--)
#define fore(e, v) for(auto&& e : v)
#define all(a) begin(a), end(a)
#define si(a) (int)(size(a))
#define lb(v, x) (lower_bound(all(v), x) - begin(v))
#define eb emplace_back

template<typename T, typename S> bool chmin(T& a, const S& b) { return a > b ? a = b, 1 : 0; }
template<typename T, typename S> bool chmax(T& a, const S& b) { return a < b ? a = b, 1 : 0; }

const int INF = 1e9 + 100;
const ll INFL = 3e18 + 100;

#define i128 __int128_t

struct _ {
    _() { cin.tie(0)->sync_with_stdio(0), cout.tie(0); }
} __;

template<class S, S (*op)(S, S), S (*e)()> struct segtree {
    segtree(int n) : segtree(vector<S>(n, e())) {}
    segtree(const vector<S>& v) : n(si(v)) {
        s = bit_ceil(unsigned(n));
        log = countr_zero(unsigned(s));
        d = vector<S>(2 * s, e());
        rep(i, n) d[s + i] = v[i];
        per(i, s, 1) update(i);
    }
    void set(int p, S x) {
        d[p += s] = x;
        rep(i, 1, log + 1) update(p >> i);
    }
    S prod(int l, int r) const {
        S sml = e(), smr = e();
        l += s, r += s;
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1, r >>= 1;
        }
        return op(sml, smr);
    }
    S all_prod() const { return d[1]; }
    template<typename F> int max_right(int l, F f) const {
        if (l == n) return n;
        l += s;
        S sm = e();
        do {
            while (~l & 1) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < s) {
                    l <<= 1;
                    if (f(op(sm, d[l]))) sm = op(sm, d[l++]);
                }
                return l - s;
            }
            sm = op(sm, d[l++]);
        } while ((l & -l) != l);
        return n;
    }
    template<typename F> int min_left(int r, F f) const {
        if (!r) return 0;
        r += s;
        S sm = e();
        do {
            r--;
            while (r > 1 and r & 1) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < s) {
                    r = (2* r + 1);
                    if (f(op(d[r], sm))) sm = op(d[r--], sm);
                }
                return r + 1 - s;                
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

    private:
    int n, s, log;
    vector<S> d;
    void update(int k) { d[k] = op(d[k * 2], d[k * 2 + 1]); }
};

using S = pll;
S S_op(S a, S b) {
    return max(a, b);
}
S S_e() {
    return {-1, -1};
}
using vpl = vector<pll>;
// vl calc_left_par(vl H) {
//     ll N = H.size();
//     vl par(N, -1);
//     vl stk;
//     rep(i, N) {
//         while (stk.size() > 0 && H[stk.back()] < H[i]) stk.pop_back();
//         if (stk.size() > 0) par[i] = stk.back();
//         stk.eb(i);
//     }
//     return par;
// }
// vpl calc_lr_par(vl H) {
//     ll N = H.size();
//     vl left_par = calc_left_par(H);
//     reverse(all(H));
//     vl right_par = calc_left_par(H);
//     reverse(all(right_par));
//     rep(i, N) {
//         if (right_par[i] != -1) {
//             right_par[i] = N - 1 - right_par[i];
//         }
//     }
//     vpl ret(N);
//     rep(i, N) ret[i] = {left_par[i], right_par[i]};
//     return ret;
// }

vl calc_par(vl H) {
    ll N = H.size();
    vl par(N, -1);
    vl stk;
    rep(i, N) {
        ll last = -1;
        while (stk.size() > 0 && H[stk.back()] < H[i]) {
            last = stk.back();
            stk.pop_back();
        }
        if (last != -1) par[last] = i;
        if (stk.size() > 0) par[i] = stk.back();
        stk.eb(i);
    }
    return par;
}

struct T {
    ll max;
    ll lost_max;
};

int main() {
    ll N;
    cin >> N;
    vl H(N);
    rep(i, N) cin >> H[i];
    
    vpl sort_H(N);
    rep(i, N) sort_H[i] = {H[i], i};
    sort(all(sort_H));

    using vT = vector<T>;
    vl par_list = calc_par(H);
    // rep(i, N) cout << par_list[i] << " ";
    // cout << endl;
    
    vT dp(N);
    rep(i, N) {
        dp[i] = {0, 0};
    }
    ll ans = 0;
    for (auto [h, i] : sort_H) {
        chmax(ans, dp[i].max);
        if (h == N) break;
        chmax(ans, 1 + dp[i].max + dp[i].lost_max);

        ll par = par_list[i];
        chmax(ans, 1 + dp[par].max + dp[i].max);
        ll tmp = 1 + dp[i].max;
        chmax(dp[par].lost_max, min(tmp, dp[par].max));
        chmax(dp[par].lost_max, dp[i].lost_max);
        dp[par].max = max(tmp, dp[par].max);
    }
    // rep(i, N) {
    //     cout << dp[i].max << " " << dp[i].lost_max << "\n";
    // }
    cout << ans << "\n";
}
accuracy: 1
time_ms: 130
memory_kb: 51000
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define foa(s, v) for(auto& s : v)
#define rng(i, l, r) for(int i = int(l); i < int(r); i++)
#define rep(i, n) rng(i, 0, n)
#define sz(x) int(x.size())
#define all(x) begin(x), end(x)

template <class T>
bool chmax(T& a, T b) {
	return a < b ? a = b, true : false;
}
template <class T>
bool chmin(T& a, T b) {
	return a > b ? a = b, true : false;
}

int n;

void solve() {
	vector<int> h(n);
	foa(x, h) {
		cin >> x;
		x--;
	}

	set<int> pivots = {-1, n};

	vector<pair<int, int>> val_pos;
	rep(i, n) val_pos.emplace_back(h[i], i);

	sort(all(val_pos));
	reverse(all(val_pos));

	vector<int> par(n, -1);

	const int rt = val_pos[0].second;

	auto update = [&](int cur, int nxt) {
		if(nxt < 0 || nxt >= n) return false;
		if(cur < 0 || cur >= n) return true;
		return h[cur] > h[nxt];
	};

	for(auto [v, p] : val_pos) {
		int lef = *prev(pivots.lower_bound(p)) + 1;
		int rig = *pivots.upper_bound(p);

		if(update(par[p], lef-1)) par[p] = lef-1;
		if(update(par[p], rig)) par[p] = rig;

		pivots.insert(p);
	}

	vector<int> max_path(n, 0), res(n, 0), lrsum(n, 0);
	reverse(all(val_pos));

	for(auto [val, pos] : val_pos) {
		chmax(res[pos], lrsum[pos]);

		const int pr = par[pos];
		if(pos != rt) {
			chmax(max_path[pr], max_path[pos] + 1);
			lrsum[pr] += max_path[pos] + 1;
			chmax(res[pr], res[pos] + 1);
		}
	}

	cout << (res[rt]) << endl;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	while(cin >> n) solve();
}
accuracy: 1
time_ms: 770
memory_kb: 77704
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;
//using mint = modint998244353;

//多倍長整数//
//#include <boost/multiprecision/cpp_int.hpp>
//namespace mp = boost::multiprecision;
//using bint = mp::cpp_int;

const int INF = 1e9;
const int MOD = 998244353;
const long long LINF = 4e18;

using ll = long long;
using vi = vector<int>;
using vl = vector<long long>;
using vs = vector<string>;
using vc = vector<char>;
using vb = vector<bool>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vvvvi = vector<vector<vector<vector<int>>>>;
using vvl = vector<vector<long long>>;
using vvvl = vector<vector<vector<long long>>>;
using vvvvl = vector<vector<vector<vector<long long>>>>;
using vvc = vector<vector<char>>;
using vvb = vector<vector<bool>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvvb = vector<vector<vector<vector<bool>>>>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define dump(x)  cout << #x << " = " << (x) << endl;
#define Yes(n) cout << ((n) ? "Yes" : "No"  ) << endl
#define ALL(obj) (obj).begin(),(obj).end()

template<class S, S (*op)(S, S), S (*e)()> struct segtree {
   segtree() : segtree(0) {}
   segtree(int n) : segtree(vector<S>(n, e())) {}
   segtree(const vector<S>& v) : n(v.size()) {
      s = bit_ceil(unsigned(n));
      log = countr_zero(unsigned(s));
      d = vector<S>(2 * s, e());
      for(int i = 0; i < n; i++) d[s + i] = v[i];
      for(int i = s - 1; i >= 1; i--) update(i);
   }

   void set(int p, S x) {
      p += s;
      d[p] = x;
      for(int i = 1; i <= log; i++) update(p >> i);
   }

   S get(int p) { return d[p + s]; }

   S prod(int l, int r) const {
      S sml = e(), smr = e();
      l += s, r += s;
      while(l < r) {
         if(l & 1) sml = op(sml, d[l++]);
         if(r & 1) smr = op(d[--r], smr);
         l >>= 1, r >>= 1;
      }
      return op(sml, smr);
   }

   S all_prod() const { return d[1]; }

   template<typename F> int max_right(int l, F f) const {
      if(l == n) return n;
      l += s;
      S sm = e();
      do {
         while(~l & 1) l >>= 1;
         if(!f(op(sm, d[l]))) {
            while(l < s) {
               l <<= 1;
               if(f(op(sm, d[l]))) sm = op(sm, d[l++]);
            }
            return l - s;
         }
         sm = op(sm, d[l++]);
      } while((l & -l) != l);
      return n;
   }

   template<typename F> int min_left(int r, F f) const {
      if(!r) return 0;
      r += s;
      S sm = e();
      do {
         r--;
         while(r > 1 and r & 1) r >>= 1;
         if(!f(op(d[r], sm))) {
            while(r < s) {
               r = (2 * r + 1);
               if(f(op(d[r], sm))) sm = op(d[r--], sm);
            }
            return r + 1 - s;
         }
         sm = op(d[r], sm);
      } while((r & -r) != r);
      return 0;
   }

   private:
   int n, s, log;
   vector<S> d;
   void update(int k) { d[k] = op(d[k * 2], d[k * 2 + 1]); }
};

pair<int,int> op(pair<int,int> a,pair<int,int> b){return max(a,b);}
pair<int,int> e(){return {-1,-1};}

segtree<pair<int,int>,op,e> seg;

pair<int,int> f(int l,int r){//dia,h
	if(l == r) return {-1e7,0};
	if(l + 1 == r) return {0,1};
	int p = seg.prod(l,r).second;
	pair<int,int> a = f(l,p);
	pair<int,int> b = f(p + 1,r);
	return {max({a.first + 1,b.first + 1,a.second + b.second}),max(a.second + 1,b.second + 1)};
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int n;
	cin >> n;
	vector<pair<int,int>> h(n);
	rep(i,n) cin >> h[i].first;
	rep(i,n) h[i].second = i;
	seg = segtree<pair<int,int>,op,e> (h);
	cout << f(0,n).first << endl;
	return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 74484
final_rank: 2

code_snippet: #include <algorithm>
#include <iostream>
#include <limits>
#include <stack>
#include <vector>

using namespace std;

const int INF = numeric_limits<int>::max();
int n;
vector<int> H(10000000), L(10000000, -1), R(10000000, -1);
int ans = 0;

void calc_left_path(vector<int> &ret, bool reverse = false) {
    int step = reverse ? -1 : 1;
    stack<pair<int, int>> s;
    s.push({INF, -1});
    for (int i = (reverse ? n - 1 : 0); (reverse ? i >= 0 : i < n); i += step) {
        int p = -1;
        while (s.top().first < H[i]) {
            p = s.top().second;
            s.pop();
        }
        ret[i] = p;
        s.push({H[i], i});
    }
}

int solve(int v, int depth) {
    if (v == -1) {
        return 0;
    }
    // cout << v << " " << depth << endl;
    int left = solve(L[v], depth + 1);
    int right = solve(R[v], depth + 1);
    ans = max(ans, depth + left + right);
    return max(left, right) + 1;
}

int main() {
    cin >> n;
    // H.resize(n);
    // L.resize(n, -1);
    // R.resize(n, -1);
    // cout << endl;
    // cout << "L: ";
    // for (int i = 0; i < n; ++i) {
    //     cout << L[i] << " ";
    // }
    // cout << endl;
    // cout << "R: ";
    // for (int i = 0; i < n; ++i) {
    //     cout << R[i] << " ";
    // }
    // cout << endl;
    for (int i = 0; i < n; ++i) {
        cin >> H[i];
    }
    // cout << "H: ";
    // for (int i = 0; i < n; ++i) {
    //     cout << H[i] << " ";
    // }
    calc_left_path(L);
    calc_left_path(R, true);
    // cout << "L: ";
    // for (int i = 0; i < n; ++i) {
    //     cout << L[i] << " ";
    // }
    // cout << endl;
    // cout << "R: ";
    // for (int i = 0; i < n; ++i) {
    //     cout << R[i] << " ";
    // }
    // cout << endl;
    solve(max_element(H.begin(), H.end()) - H.begin(), 0);
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 167100
final_rank: 11

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

template <typename M, typename N, M (*f)(M, M), M (*g)(M, N), M (*m1)()>
struct SegmentTree {
    int sz, n;
    vector<M> data;
    SegmentTree(int _n = 0) : n(_n) {
        sz = 1;
        while (sz < _n)
            sz <<= 1;
        data.assign(2 * sz, m1());
    }
    void run(vector<M> &v) {
        for (int i = 0; i < (int)v.size(); i++)
            data[i + sz] = v[i];
        for (int k = sz - 1; k > 0; k--)
            data[k] = f(data[2 * k], data[2 * k + 1]);
    }
    void set(int k, const M &x) {
        k += sz;
        data[k] = x;
        while (k >>= 1)
            data[k] = f(data[2 * k], data[2 * k + 1]);
    }
    void update(int k, const N &x) {
        k += sz;
        data[k] = g(data[k], x);
        while (k >>= 1)
            data[k] = f(data[2 * k], data[2 * k + 1]);
    }
    M query(int a, int b) {
        M L = m1(), R = m1();
        for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
            if (a & 1)
                L = f(L, data[a++]);
            if (b & 1)
                R = f(data[--b], R);
        }
        return f(L, R);
    }
    M operator[](const int &k) const {
        return data[k + sz];
    }
    vector<M> get() {
        return {data.begin() + sz, data.begin() + sz + n};
    }
    template <class F> int max_right(int L, F ch) const {
        int l = sz + L, w = 1;
        M ansL = m1();
        for (; L + w <= sz; l >>= 1, w <<= 1)
            if (l & 1) {
                if (not ch(f(ansL, data[l])))
                    break;
                ansL = f(ansL, data[l++]);
                L += w;
            }
        while (l <<= 1, w >>= 1) {
            if (L + w <= sz && ch(f(ansL, data[l]))) {
                ansL = f(ansL, data[l++]);
                L += w;
            }
        }
        return L;
    }
    template <class F> int min_left(int R, F ch) const {
        int r = sz + R, w = 1;
        M ansR = m1();
        for (; R - w >= 0; r >>= 1, w <<= 1)
            if (r & 1) {
                if (not ch(f(data[r - 1], ansR)))
                    break;
                ansR = f(data[--r], ansR);
                R -= w;
            }
        while (r <<= 1, w >>= 1) {
            if (R - w >= 0 && ch(f(data[r - 1], ansR))) {
                ansR = f(data[--r], ansR);
                R -= w;
            }
        }
        return R;
    }
};

/**
 * @brief Segment Tree
 */

int f(int A, int B) {return max(A,B);}
int g(int A, int B) {return B;}
int e() {return -inf;}

int main() {
    int N;
    cin >> N;
    vector<int> A(N), IA(N);
    rep(i,0,N) cin >> A[i], A[i]--, IA[A[i]] = i;
    SegmentTree<int,int,f,g,e> Seg(N);
    Seg.run(A);
    vector<int> High(N,-inf), Diam(N,-inf);
    auto DFS = [&](auto self, int L, int R) -> pair<int,int> {
        if (L==R) return {-inf,-inf};
        int M = IA[Seg.query(L,R)];
        pair<int,int> Left = self(self,L,M);
        pair<int,int> Right = self(self,M+1,R);
        High[M] = 0, Diam[M] = 0;
        chmax(High[M],Left.first+1);
        chmax(High[M],Right.first+1);
        chmax(Diam[M],Left.second+1);
        chmax(Diam[M],Right.second+1);
        chmax(Diam[M],Left.first+Right.first+2);
        return {High[M],Diam[M]};
    };
    auto ANS = DFS(DFS,0,N);
    cout << ANS.second << endl;
}
accuracy: 1
time_ms: 240
memory_kb: 104992
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
template<int mod>istream &operator>>(istream &is,static_modint<mod> &a){long long b;is>>b;a=b;return is;}
istream &operator>>(istream &is,modint &a){long long b;cin>>b;a=b;return is;}
#endif
#ifdef LOCAL
#include "debug.h"
#else
#define debug(...) static_cast<void>(0)
#define debugg(...) static_cast<void>(0)
#define esper(...) static_cast<void>(0)
template<typename T1,typename T2>ostream &operator<<(ostream &os,const pair<T1,T2>&p){os<<p.first<<' '<<p.second;return os;}
#endif
using ll=long long;
using ull=unsigned long long;
using P=pair<ll,ll>;
template<typename T>using minque=priority_queue<T,vector<T>,greater<T>>;
template<typename T>bool chmax(T &a,const T &b){return (a<b?(a=b,true):false);}
template<typename T>bool chmin(T &a,const T &b){return (a>b?(a=b,true):false);}
template<typename T1,typename T2>istream &operator>>(istream &is,pair<T1,T2>&p){is>>p.first>>p.second;return is;}
template<typename T>istream &operator>>(istream &is,vector<T> &a){for(auto &i:a)is>>i;return is;}
template<typename T1,typename T2>void operator++(pair<T1,T2>&a,int n){a.first++,a.second++;}
template<typename T1,typename T2>void operator--(pair<T1,T2>&a,int n){a.first--,a.second--;}
template<typename T>void operator++(vector<T>&a,int n){for(auto &i:a)i++;}
template<typename T>void operator--(vector<T>&a,int n){for(auto &i:a)i--;}
#define reps(i,a,n) for(int i=(a);i<(n);i++)
#define rep(i,n) reps(i,0,n)
#define all(x) x.begin(),x.end()
#define pcnt(x) __builtin_popcountll(x)
#define fin(x) return cout<<x<<'\n',static_cast<void>(0)
ll myceil(ll a,ll b){return (a+b-1)/b;}
template<typename T,size_t n,size_t id=0>
auto vec(const int (&d)[n],const T &init=T()){
  if constexpr (id<n)return vector(d[id],vec<T,n,id+1>(d,init));
  else return init;
}
void SOLVE();
int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout<<fixed<<setprecision(16);
  #ifdef LOCAL
  clock_t start=clock();
  #endif
  int testcase=1;
  //cin>>testcase;
  for(int i=0;i<testcase;i++){
    SOLVE();
  }
  #ifdef LOCAL
  cerr<<"time:";
  cerr<<(clock()-start)/1000;
  cerr<<"ms\n";
  #endif
}
void SOLVE(){
  int n;
  cin>>n;
  vector<int>h(n);
  cin>>h;
  h--;
  stack<int>st;
  vector<int>p(n,-1);
  rep(i,n){
    int f=-1;
    while(!st.empty()){
      int x=st.top();
      if(h[x]<h[i])f=x,st.pop();
      else break;
    }
    if(f!=-1)p[f]=i;
    if(!st.empty())p[i]=st.top();
    st.push(i);
  }
  vector<int>left(n,-1),right(n,-1);
  rep(i,n)if(p[i]!=-1){
    (i<p[i]?left:right)[p[i]]=i;
  }
  int ans=0;
  auto dfs=[&](auto self,int x,int dep)->int {
    chmax(ans,dep);
    int l=-1e8,r=-1e8;
    if(left[x]!=-1)l=self(self,left[x],dep+1);
    if(right[x]!=-1)r=self(self,right[x],dep+1);
    chmax(ans,l+r-dep);
    return max({l,r,dep});
  };
  dfs(dfs,max_element(all(h))-h.begin(),0);
  cout<<ans<<endl;
}
accuracy: 1
time_ms: 80
memory_kb: 100752
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

template <typename S, typename Op>
struct SegTree {
    int n, sz, height;
    vector<S> data;
    Op op;
    S inf;

    void update(int k) { data[k] = op(data[k*2], data[k*2+1]); }

    SegTree(int n_, Op op_, S inf_) : n(n_), op(op_), inf(inf_) {
        sz = 1;
        height = 0;
        while(sz < n) {
            sz <<= 1;
            height++;
        }
        data.resize(sz*2, inf);
    }

    S get(int i) { return data[sz+i]; }
    void set(int i, S x) {
        i += sz;
        data[i] = x;
        for(int h = 1; h <= height; h++) {
            update(i >> h);
        }
    }
    S prod(int l, int r) {
        S left = inf, right = inf;
        l += sz, r += sz;
        while(l < r) {
            if(l & 1) left = op(left, data[l++]);
            if(r & 1) right = op(data[--r], right);
            l >>= 1;
            r >>= 1;
        }
        return op(left, right);
    }

    template <typename F>
    int max_right(int l, F f) {
        assert(f(inf));
        if(l == n) return n;
        l += sz;
        while(l % 2 == 0) l >>=1;
        S sum = inf;
        while(f(op(sum, data[l]))) {
            if(__builtin_clz(l) != __builtin_clz(l+1)) return n;
            sum = op(sum, data[l]);
            l++;
            while(l % 2 == 0) l >= 1;
        }
        while(l < sz) {
            if(!f(op(sum, data[l*2]))) l *= 2;
            else {
                sum = op(sum, data[l*2]);
                l = l * 2 + 1;
            }
        }
        return l - sz;
    }
};

void chmax(int &a, int b) { a = max(a, b); }


int main() {
    int n;
    cin >> n;
    vector<int> h(n), rh(n);
    for(int i = 0; i < n; i++) {
        cin >> h[i];
        h[i]--;
        rh[h[i]] = i;
    }

    int ans = 0;
    SegTree seg(n, [&](int i, int j){return max(i, j);}, -(1<<30));

    for(int i = 0 ; i < n; i ++) seg.set(i, h[i]);

    vector<int> le_min(n, -1), ri_min(n, -1);

    vector<int> le_ans(n, 0), ri_ans(n, 0);

    auto dfs = [&](auto dfs, int le, int ri) -> int {
        if(ri == le) return -1;
        int now = rh[seg.prod(le, ri)];
        le_min[now] = le - 1;
        ri_min[now] = ri;
        le_ans[now] = dfs(dfs, le, now) + 1;
        ri_ans[now] = dfs(dfs, now + 1, ri) + 1;
        ans = max(ans, le_ans[now] + ri_ans[now]);
        return max(le_ans[now], ri_ans[now]);
    };
    dfs(dfs, 0, n) ;
    int inf = (1 << 30);

    // vector<int> le_lis(n, 0), ri_lis(n, 0);
    // {
    //     SegTree seg1(n, [&](int i, int j){return max(i, j);}, -(1<<30));
    //     for(int i = 0; i < n; i ++) {
    //         int ret = max(0, seg1.prod(h[i], n) + 1);
    //         le_lis[i] = ret;
    //         seg1.set(h[i], ret);
    //     }
    //     SegTree seg2(n, [&](int i, int j){return max(i, j);}, -(1<<30));
    //     for(int i = n - 1; i >= 0; i --) {
    //         int ret = max(0, seg2.prod(h[i], n) + 1);
    //         ri_lis[i] = ret;
    //         seg2.set(h[i], ret);
    //     }
    // }

    SegTree seg1(n, [&](int i, int j){return max(i, j);}, -(1<<30));
    SegTree seg2(n, [&](int i, int j){return max(i, j);}, -(1<<30));

    vector<int> le_lis(n, 0), ri_lis(n, 0);

    for(int i = 0; i < n; i ++) {
        if(le_min[i] != -1) le_lis[i] = le_lis[le_min[i]] + 1;
    }
    for(int i = n - 1; i >= 0 ; i --) {
        if(ri_min[i] != n) ri_lis[i] = ri_lis[ri_min[i]] + 1;
    }

    for(int i = 0 ; i < n; i ++) {
        seg1.set(i, le_ans[i] + le_lis[i]);
        seg2.set(i, ri_ans[i] + ri_lis[i]);
        // cout << le_lis[i] << " " << ri_lis[i] << endl;
    }

    
    for(int i = 1; i < n; i ++) {
        chmax(ans, seg1.prod(0, i) + seg2.prod(i, n) + 1);
    }

    
    cout << ans << endl;
}
accuracy: 1
time_ms: 420
memory_kb: 168256
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

template <typename S, typename Op>
struct SegTree {
    int n, sz, height;
    vector<S> data;
    Op op;
    S inf;

    void update(int k) { data[k] = op(data[k*2], data[k*2+1]); }

    SegTree(int n_, Op op_, S inf_) : n(n_), op(op_), inf(inf_) {
        sz = 1;
        height = 0;
        while(sz < n) {
            sz <<= 1;
            height++;
        }
        data.resize(sz*2, inf);
    }

    S get(int i) { return data[sz+i]; }
    void set(int i, S x) {
        i += sz;
        data[i] = x;
        for(int h = 1; h <= height; h++) {
            update(i >> h);
        }
    }
    S prod(int l, int r) {
        S left = inf, right = inf;
        l += sz, r += sz;
        while(l < r) {
            if(l & 1) left = op(left, data[l++]);
            if(r & 1) right = op(data[--r], right);
            l >>= 1;
            r >>= 1;
        }
        return op(left, right);
    }

    template <typename F>
    int max_right(int l, F f) {
        assert(f(inf));
        if(l == n) return n;
        l += sz;
        while(l % 2 == 0) l >>=1;
        S sum = inf;
        while(f(op(sum, data[l]))) {
            if(__builtin_clz(l) != __builtin_clz(l+1)) return n;
            sum = op(sum, data[l]);
            l++;
            while(l % 2 == 0) l >= 1;
        }
        while(l < sz) {
            if(!f(op(sum, data[l*2]))) l *= 2;
            else {
                sum = op(sum, data[l*2]);
                l = l * 2 + 1;
            }
        }
        return l - sz;
    }
};

void chmax(int &a, int b) { a = max(a, b); }


int main() {
    int n;
    cin >> n;
    vector<int> h(n), rh(n);
    for(int i = 0; i < n; i++) {
        cin >> h[i];
        h[i]--;
        rh[h[i]] = i;
    }

    int ans = 0;
    SegTree seg(n, [&](int i, int j){return max(i, j);}, -(1<<30));

    for(int i = 0 ; i < n; i ++) seg.set(i, h[i]);

    vector<int> le_min(n, -1), ri_min(n, -1);

    vector<int> le_ans(n, 0), ri_ans(n, 0);

    auto dfs = [&](auto dfs, int le, int ri) -> int {
        if(ri == le) return -1;
        int now = rh[seg.prod(le, ri)];
        le_min[now] = le - 1;
        ri_min[now] = ri;
        le_ans[now] = dfs(dfs, le, now) + 1;
        ri_ans[now] = dfs(dfs, now + 1, ri) + 1;
        ans = max(ans, le_ans[now] + ri_ans[now]);
        return max(le_ans[now], ri_ans[now]);
    };
    dfs(dfs, 0, n) ;

    int inf = (1 << 30);

    for(int i = 1; i < n; i ++) {
        int le = rh[seg.prod(0, i)];
        int ri = rh[seg.prod(i, n)];
        int lele = seg.prod(0, le);
        int leri = seg.prod(le + 1, i);
        int rile = seg.prod(i, ri);
        int riri = seg.prod(ri + 1, n);
        int lem = 0, rim = 0;
        if(lele != -inf) chmax(lem, ri_ans[rh[lele]] + 1);
        if(leri != -inf) chmax(lem, le_ans[rh[leri]] + 1);
        if(rile != -inf) chmax(rim, ri_ans[rh[rile]] + 1);
        if(riri != -inf) chmax(rim, le_ans[rh[riri]] + 1);
        chmax(ans, lem + rim + 1);
    }

    
    cout << ans << endl;
}
accuracy: 0.006134969325153374
time_ms: 410
memory_kb: 34644
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
using pi = pair<int, int>;
using vi = vector<int>;
using vl = vector<ll>;
using vpi = vector<pi>;
using vvi = vector<vi>;
using vvl = vector<vl>;

struct segtree{
    int sz,ofs;
    vpi dat;
    pi e;

    pi merge(pi x,pi y){
        if(x.first>y.first) return x;
        else return y;
    }

    pi subquery(int ql,int qr,int left,int right,int i){
        if(qr<=left||right<=ql) return e;
        if(ql<=left&&right<=qr) return dat[i];
        int mid=(left+right)/2;
        pi al=subquery(ql,qr,left,mid,i*2);
        pi ar=subquery(ql,qr,mid,right,i*2+1);
        return merge(al,ar);
    }

    segtree(vpi &init):e({-1,-1}){
        sz=1;
        while(sz<init.size()) sz<<=1;
        ofs=sz-1;
        dat.resize(sz*2,e);
        for(int i=0;i<init.size();++i) dat[sz+i]=init[i];
        for(int i=ofs;i>=1;--i) dat[i]=merge(dat[i*2],dat[i*2+1]);
    }

    void update(int k,pi v){
        k+=ofs;
        dat[k]=v;
        while(k>>=1) dat[k]=merge(dat[k*2],dat[k*2+1]);
    }

    pi query(int l,int r){
        return subquery(l,r,1,sz+1,1);
    }
};

int main(){
    int n; cin >> n;
    vpi ini(n);
    for(int i = 0; i < n; ++i){
        int h; cin >> h;
        ini[i] = {h, i + 1};
    }
    segtree seg(ini);

    auto rec = [&](auto self, int l, int r) -> pi {
        if(l >= r){
            return {-n * 10, -n * 10};
        }
        // cerr << "Rec : " << l << ", " << r << endl;
        pi ret = {0, 0};
        if(l + 1 == r) return ret;
        int m = seg.query(l, r).second;
        pi left = self(self, l, m);
        pi right = self(self, m + 1, r);
        if(left.first + 1 > ret.first){
            ret.first = left.first + 1;
            ret.second = left.second + 1;
        }
        if(right.first + 1 > ret.first){
            ret.first = right.first + 1;
            ret.second = right.second + 1;
        }
        if(left.second + right.second + 2 > ret.first){
            ret.first = left.second + right.second + 2;
            ret.second = max(left.second, right.second) + 1;
        }
        // cerr << "Rec : " << l << ", " << r << " -> " << ret.first << ", " << ret.second << endl;
        return ret;
    };

    cout << rec(rec, 1, n + 1).first << endl;
}
accuracy: 1
time_ms: 350
memory_kb: 136768
final_rank: 10

code_snippet: #include <bits/stdc++.h>

#define rep(i,s,n) for(int i = int(s); i < int(n); i++)
#define rrep(i,s,n) for(int i = int(n) - 1; i >= int(s); i--)
#define all(v) (v).begin(), (v).end()

using ll = long long;
using ld = long double;
using ull = unsigned long long;

template<class T>
bool chmin(T &a, T b) {
    if(a <= b) return false;
    a = b;
    return true;
}

template<class T>
bool chmax(T &a, T b) {
    if(a >= b) return false;
    a = b;
    return true;
}

template<class S, S (*op)(S, S), S (*e)()>
struct segtree {
private:
    int n;
    int sz;
    int lg2;
    std::vector<S> data;

    void update(int i) {
        data[i] = op(data[2 * i], data[2 * i + 1]);
    }
public:
    segtree(const std::vector<S> &v) : n(v.size()) {
        lg2 = 0;
        while((1<<lg2) < n) lg2++;
        sz = 1<<lg2;
        data = std::vector<S>(2 * sz, e());
        rep(i,0,n) data[i + sz] = v[i];
        rrep(i,0,sz) update(i);
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= n);
        S sml = e(), smr = e();
        l += sz;
        r += sz;
        while(l < r) {
            if(l & 1) sml = op(sml, data[l++]);
            if(r & 1) smr = op(data[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_prod() {
        return data[1];
    }
};

using S = std::pair<int,int>;

S op(S a, S b) {
    return a > b ? a : b;
}

S e() {
    return {-1, -1};
}

int main() {
    int n;
    std::cin >> n;
    std::vector<int> h(n);
    rep(i,0,n) std::cin >> h[i];
    std::vector<std::pair<int,int>> p(n);
    rep(i,0,n) p[i] = {h[i], i};
    segtree<S, op, e> seg(p);
    int ans = 0;
    auto f = [&](auto &&self, int l, int r) -> std::pair<int,int> {
        if(l == r) return {0, 0};
        if(r - l == 1) return {1, 1};
        int i = seg.prod(l, r).second;
        assert(0 <= i && i < n);
        auto [a, b] = self(self, l, i);
        auto [c, d] = self(self, i+1, r);
        int t = std::max(b + 1, d + 1);
        chmax(t, a + c + 1);
        int s = std::max(a + 1, c + 1);
        chmax(ans, t - 1);
        return {s, t};
    };
    f(f, 0, n);
    std::cout << ans << '\n';
}
accuracy: 1
time_ms: 240
memory_kb: 93592
final_rank: 5

code_snippet: #include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

class segtree {
private:
	int sz;
	vector<int> val;
	vector<int> lazy;
	void push(int k) {
		val[k] += lazy[k];
		if (k < sz) {
			lazy[k * 2] += lazy[k];
			lazy[k * 2 + 1] += lazy[k];
		}
		lazy[k] = 0;
	}
	void rangeadd(int a, int b, int k, int l, int r, int x) {
		push(k);
		if (r <= a || b <= l) return;
		if (a <= l && r <= b) {
			lazy[k] += x;
			push(k);
			return;
		}
		rangeadd(a, b, k * 2, l, (l + r) >> 1, x);
		rangeadd(a, b, k * 2 + 1, (l + r) >> 1, r, x);
		val[k] = max(val[k * 2], val[k * 2 + 1]);
	}
public:
	segtree() : sz(0), val(vector<int>()), lazy(vector<int>()) {}
	segtree(int n) {
		sz = 1;
		while (sz < n) {
			sz *= 2;
		}
		val = vector<int>(sz * 2, 0);
		lazy = vector<int>(sz * 2, 0);
	}
	void rangeadd(int l, int r, int x) {
		rangeadd(l, r, 1, 0, sz, x);
	}
	int getmax() {
		return val[1];
	}
};	

vector<int> calc(int N, const vector<int>& H) {
	vector<int> l(N), answer(N + 1);
	vector<int> st;
	segtree seg(N);
	for (int i = 0; i < N; i++) {
		int last = -1;
		while (!st.empty() && H[st.back()] < H[i]) {
			last = st.back();
			st.pop_back();
		}
		l[i] = (last != -1 ? l[last] : i);
		seg.rangeadd(l[i], i, 1);
		seg.rangeadd(i, i + 1, st.size() + 1);
		st.push_back(i);
		answer[i + 1] = seg.getmax();
	}
	return answer;
}

int main() {
	// step #1. read input
	int N;
	cin >> N;
	vector<int> H(N);
	for (int i = 0; i < N; i++) {
		cin >> H[i];
	}
	
	// step #2. calculate sub-answers
	int max_point = max_element(H.begin(), H.end()) - H.begin();
	vector<int> hl(H.begin(), H.begin() + max_point);
	vector<int> hr(H.begin() + max_point + 1, H.end());
	vector<int> al = calc(hl.size(), hl);
	reverse(hl.begin(), hl.end());
	vector<int> bl = calc(hl.size(), hl);
	reverse(bl.begin(), bl.end());
	vector<int> ar = calc(hr.size(), hr);
	reverse(hr.begin(), hr.end());
	vector<int> br = calc(hr.size(), hr);
	reverse(br.begin(), br.end());
	
	// step #3. calculate answer
	int answer = 0;
	for (int i = 0; i < int(al.size()); i++) {
		answer = max(answer, al[i] + bl[i]);
	}
	for (int i = 0; i < int(ar.size()); i++) {
		answer = max(answer, ar[i] + br[i]);
	}
	if (!al.empty() && !ar.empty()) {
		answer = max(answer, al.back() + ar.back());
	}
	
	// step #4. output
	cout << answer << endl;
	
	return 0;
}
accuracy: 1
time_ms: 850
memory_kb: 46944
final_rank: 9