2019牛客多校第三场 F.Planting Trees(单调队列)

题目明确表示要用n3的的算法做。
因此枚举矩阵的上下边界和右边界,再用两个单调队列维护左边界。

#include 

using namespace std;
typedef long long ll;

const int maxn = 505;

int t, n, m, num[maxn][maxn];

int maxx[maxn], minn[maxn];
int h1, h2, t1, t2, qmax[maxn], qmin[maxn];

void solve() {
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        for (int e = 1; e <= n; ++e) {
            maxx[e] = 0, minn[e] = 99999999;
        }
        for (int j = i; j <= n; ++j) {
            h1 = h2 = 1, t1 = t2 = 0;
            for (int k = 1, p = 0; k <= n; ++k) {
                maxx[k] = max(maxx[k], num[j][k]);
                minn[k] = min(minn[k], num[j][k]);

                while (h1 <= t1 && maxx[qmax[t1]] < maxx[k]) {
                    --t1;
                }
                while (h2 <= t2 && minn[qmin[t2]] > minn[k]) {
                    --t2;
                }
                qmax[++t1] = k, qmin[++t2] = k;

                while (h1 <= t1 && h2 <= t2 && maxx[qmax[h1]] - minn[qmin[h2]] > m) {
                    if (qmax[h1] < qmin[h2]) {
                        p = qmax[h1++];
                    } else {
                        p = qmin[h2++];
                    }
                }
                ans = max(ans, (j - i + 1) * (k - p));
            }
        }
    }
    printf("%d\n", ans);
}

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                scanf("%d", &num[i][j]);
            }
        }
        solve();
    }
    return 0;
}

你可能感兴趣的:(ACM,单调队列)