This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
// AM + DG
#include "towers.h"
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int, int> pi;
typedef pair<ll, ll> pll;
typedef vector<pi> vpi;
typedef vector<pll> vpll;
typedef vector<vpi> vvpi;
typedef vector<vpll> vvpll;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef short int si;
typedef vector<si> vsi;
typedef vector<vsi> vvsi;
#define IOS ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
#define L(varll, mn, mx) for(ll varll = (mn); varll < (mx); varll++)
#define LR(varll, mx, mn) for(ll varll = (mx); varll > (mn); varll--)
#define LI(vari, mn, mx) for(int vari = (mn); vari < (mx); vari++)
#define LIR(vari, mx, mn) for(int vari = (mx); vari > (mn); vari--)
#define INPV(varvec) for(auto& varveci : (varvec)) cin >> varveci
#define fi first
#define se second
#define pb push_back
#define INF(type) numeric_limits<type>::max()
#define NINF(type) numeric_limits<type>::min()
#define TCASES int t; cin >> t; while(t--)
/*
DTree (DiffTree)
Computes the largest forward difference within a range
Formally, max l <= i <= j <= r of h[j] - h[i]
*/
struct DTreeState {
    int mn, mx, difff, diffb;
    DTreeState operator+(const DTreeState& o) const {
        if(mn == 0) return o;
        else if(o.mn == 0) return {mn, mx, difff, diffb};
        return {min(mn, o.mn), max(mx, o.mx), max(difff, o.mx - mn), max(diffb, mx - o.mn)};
    }
};
class DTree {
    public:
        int l, r;
        DTree *lt, *rt;
        DTreeState v;
        DTree(int a_l, int a_r): l(a_l), r(a_r), lt(nullptr), rt(nullptr), v({0, 0, 0}) {}
        void combine() {
            v = lt->v + rt->v; // ! Careful! Addition is noncommutative!
        }
        void build(const vi& a) {
            if(l == r) {
                v = {a[l], a[l], 0, 0};
                return;
            }
            int m = (l + r) >> 1;
            lt = new DTree(l, m);
            rt = new DTree(m + 1, r);
            lt->build(a);
            rt->build(a);
            combine();
        }
        DTreeState qry(int ql, int qr) {
            if(ql > r || qr < l) return {0, 0, 0, 0};
            if(ql == l && qr == r) {
                return v;
            }
            int m = (l + r) >> 1;
            return lt->qry(ql, min(qr, m)) + rt->qry(max(ql, m + 1) , qr);
        }
};
/*
LTree (Lease Tree)
The lease tree will compute the maximum and minimum indices to be leased
if the value of delta is D
Notice that each node has a corresponding max delta and index
Now, what if we store the deltas in increasing order? (could be decreasing too)
Then, when the value of delta is D, that means that a suffix (or prefix) would
be the values in consideration
Well, now, what if we compute the min and max indices over a prefix?
So it reduces to binary search ^^
It reduces to two binary searches, actually, so Q log^2 N per query
Conceptually, a node would have a schema of...
type Node = {
    l, r: int
    lt, rt: Node*
    deltas: [delta, ind][]
    mins: int[]
    maxs: int[]
}
*/
class LTree {
    public:
        int l, r;
        LTree *lt, *rt;
        vpi deltas;
        vi mins;
        vi maxs;
        LTree(int a_l, int a_r): l(a_l), r(a_r), deltas(), mins(), maxs() {}
        
        void combine() {
            int lds = lt->deltas.size(), rds = rt->deltas.size();
            int ldp = 0, rdp = 0;
            while(ldp < lds && rdp < rds) {
                if(lt->deltas[ldp].fi > rt->deltas[rdp].fi) {
                    deltas.pb(lt->deltas[ldp]);
                    ldp++;
                } else {
                    deltas.pb(rt->deltas[rdp]);
                    rdp++;
                }
            }
            while(ldp < lds) {
                deltas.pb(lt->deltas[ldp]);
                ldp++;
            }
            while(rdp < rds) {
                deltas.pb(rt->deltas[rdp]);
                rdp++;
            }
            int ds = deltas.size();
            mins.reserve(ds);
            maxs.reserve(ds);
            mins.pb(INF(int));
            maxs.pb(NINF(int));
            for(int i = 0; i < ds; i++) {
                mins.pb(min(mins.back(), deltas[i].se));
                maxs.pb(max(maxs.back(), deltas[i].se));
            }
        }
        void build(const vi& d) {
            if(l == r) {
                deltas.pb({d[l], l});
                mins.pb(INF(int));
                mins.pb(l);
                maxs.pb(NINF(int));
                maxs.pb(l);
                return;
            }
            int m = (l + r) >> 1;
            lt = new LTree(l, m);
            rt = new LTree(m + 1, r);
            lt->build(d);
            rt->build(d);
            combine();
        }
        pi qry(int ql, int qr, int d) {
            if(ql > r || qr < l) return {INF(int), NINF(int)};
            if(ql == l && qr == r) {
                int ds = deltas.size();
                int li = -1, ri = ds;
                while(ri - li > 1) {
                    int m = (li + ri) >> 1;
                    if(deltas[m].fi >= d) li = m;
                    else ri = m;
                }
                return {mins[li + 1], maxs[li + 1]};
            }
            int m = (l + r) >> 1;
            auto [mn1, mx1] = lt->qry(ql, min(qr, m), d);
            auto [mn2, mx2] = rt->qry(max(m + 1, ql), qr, d);
            return {min(mn1, mn2), max(mx1, mx2)};
        }
        int qry_count(int ql, int qr, int d) {
            if(ql > r || qr < l) return 0;
            if(ql == l && qr == r) {
                int ds = deltas.size();
                int li = -1, ri = ds;
                while(ri - li > 1) {
                    int m = (li + ri) >> 1;
                    if(deltas[m].fi >= d) li = m;
                    else ri = m;
                }
                return li + 1;
            }
            int m = (l + r) >> 1;
            return lt->qry_count(ql, min(qr, m), d) + rt->qry_count(max(m + 1, ql), qr, d);
        }
};
int n;
vi h;
DTree* dtr;
LTree* ltr;
vi dvals;
void init(int N, vi H) {
    n = N;
    h = H;
    // Create DTree
    dtr = new DTree(0, n - 1);
    dtr->build(h);
    // Compute critical d-values
    for(int i = 0; i < n; i++) {
        int l1 = -1, r1 = i;
        while(r1 - l1 > 1) {
            int m = (l1 + r1) >> 1;
            if(dtr->qry(m, i).mn < h[i]) l1 = m;
            else r1 = m;
        }
        int l2 = i, r2 = n;
        while(r2 - l2 > 1) {
            int m = (l2 + r2) >> 1;
            if(dtr->qry(i, m).mn < h[i]) r2 = m;
            else l2 = m;
        }
        
        int min_h = INF(int);
        if(l1 != -1) {
            min_h = min(min_h, dtr->qry(l1, i).mx);
        }
        if(r2 != n) {
            min_h = min(min_h, dtr->qry(i, r2).mx);
        }
        dvals.pb(min_h - h[i]);
    }
    ltr = new LTree(0, n - 1);
    ltr->build(dvals);
}
int max_towers(int L, int R, int D) {
    auto [li, ri] = ltr->qry(L, R, D);
    // cout << "! " << li << " " << ri << endl;
    int ans = 0;
    if(li == INF(int)) {
        // Case 1 (wow, research follows me everywhere): no leased in the range
        // Check forward and backward largest diffs
        auto state = dtr->qry(L, R);
        if(state.diffb >= D) ans++;
        if(state.difff >= D) ans++;
    } else {
        // Case 2 (res reference???): there is at least one leased in the range
        ans = ltr->qry_count(L, R, D);
        if(dtr->qry(L, li - 1).difff >= D) ans++;
        if(dtr->qry(ri + 1, R).diffb >= D) ans++;
    }
    return max(ans, 1);
}
/*
Last frontier
kodoku na hoshitachi e sasageru uta wo
Last moment
hitori de saihate e tabidatsu uta wo
Last of all
majiwaru koto no nai sekai wo
ima kaeru kara saigo ni
kimi to boku wa deau
*/
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |