This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
#ifdef tabr
#include "library/debug.cpp"
#else
#define debug(...)
#endif
struct dsu {
    vector<int> p;
    vector<int> sz;
    vector<int> mn;
    vector<int> mx;
    int n;
    dsu(int _n) : n(_n) {
        p = vector<int>(n);
        iota(p.begin(), p.end(), 0);
        sz = vector<int>(n, 1);
        mx = p;
        mn = p;
    }
    inline int get(int x) {
        if (p[x] == x) {
            return x;
        } else {
            return p[x] = get(p[x]);
        }
    }
    inline bool unite(int x, int y) {
        x = get(x);
        y = get(y);
        if (x == y) {
            return false;
        }
        p[x] = y;
        sz[y] += sz[x];
        mn[y] = min(mn[y], mn[x]);
        mx[y] = max(mx[y], mx[x]);
        return true;
    }
    inline bool same(int x, int y) {
        return (get(x) == get(y));
    }
    inline int size(int x) {
        return sz[get(x)];
    }
    inline bool root(int x) {
        return (x == get(x));
    }
};
struct sparse {
    using T = int;
    int n;
    int h;
    vector<vector<T>> table;
    T op(T x, T y) {
        return min(x, y);
    }
    sparse(const vector<T> &v) {
        n = (int) v.size();
        h = 32 - __builtin_clz(n);
        table.resize(h);
        table[0] = v;
        for (int j = 1; j < h; j++) {
            table[j].resize(n - (1 << j) + 1);
            for (int i = 0; i <= n - (1 << j); i++) {
                table[j][i] = op(table[j - 1][i], table[j - 1][i + (1 << (j - 1))]);
            }
        }
    }
    T get(int l, int r) {
        assert(l < r);
        int k = 31 - __builtin_clz(r - l);
        return op(table[k][l], table[k][r - (1 << k)]);
    }
};
long long count_rectangles(vector<vector<int>> a) {
    int h = (int) a.size();
    int w = (int) a[0].size();
    vector<vector<int>> first_ng(h, vector<int>(w, h));
    for (int j = 0; j < w; j++) {
        vector<int> s;
        for (int i = h - 1; i >= 0; i--) {
            while (!s.empty() && a[s.back()][j] < a[i][j]) {
                s.pop_back();
            }
            if (!s.empty()) {
                first_ng[i][j] = s.back();
            }
            s.emplace_back(i);
        }
    }
    debug(first_ng);
    long long res = 0;
    map<pair<int, int>, int> cnt;
    vector<vector<multiset<int>>> ng(w, vector<multiset<int>>(w));
    for (int i = 1; i < h - 1; i++) {
        vector<vector<int>> bound(w);
        map<int, vector<int>> v;
        for (int j = 0; j < w; j++) {
            v[a[i][j]].emplace_back(j);
        }
        dsu uf(w);
        for (auto p : v) {
            for (int j : p.second) {
                if (j - 1 >= 0 && a[i][j] >= a[i][j - 1]) {
                    uf.unite(j - 1, j);
                }
                if (j + 1 < w && a[i][j] >= a[i][j + 1]) {
                    uf.unite(j + 1, j);
                }
            }
            for (int j : p.second) {
                if (uf.root(j) && uf.mn[j] > 0 && uf.mx[j] < w - 1) {
                    bound[uf.mx[j]].emplace_back(uf.mn[j]);
                }
            }
        }
        sparse sp(first_ng[i - 1]);
        int up_last = 0;
        int down_last = 0;
        map<pair<int, int>, int> new_cnt;
        for (int j = 1; j < w - 1; j++) {
            if (a[i][j] >= a[i - 1][j]) {
                up_last = j;
            }
            if (a[i][j] >= a[i + 1][j]) {
                down_last = j;
            }
            for (int k : bound[j]) {
                new_cnt[make_pair(k, j)] = cnt[make_pair(k, j)];
                if (up_last < k) {
                    new_cnt[make_pair(k, j)]++;
                    ng[k][j].emplace(sp.get(k, j + 1));
                }
                new_cnt[make_pair(k, j)] -= (int) ng[k][j].count(i);
                ng[k][j].erase(i);
                if (down_last < k) {
                    res += new_cnt[make_pair(k, j)];
                }
            }
        }
        for (auto p : cnt) {
            if (!new_cnt.count(p.first)) {
                ng[p.first.first][p.first.second].clear();
            }
        }
        swap(cnt, new_cnt);
    }
    return res;
}
#ifdef tabr
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    debug(count_rectangles({{4, 8, 7, 5, 6},
                            {7, 4, 10, 3, 5},
                            {9, 7, 20, 14, 2},
                            {9, 14, 7, 3, 6},
                            {5, 7, 5, 2, 7},
                            {4, 5, 13, 5, 6}}));
    debug(count_rectangles({{5, 7, 5},
                            {9, 4, 7},
                            {9, 7, 20},
                            {7, 4, 10},
                            {4, 8, 7}}));
    return 0;
}
#endif
| # | 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... |