略微有点不一样的是,这次的悬线并没有记录R,L,数组,因为左右可延伸的长度只与竖直方向有关系。
不过这道题让我多了个疑惑,悬线法是否可以仅仅记录一边就行了,就是R或者L数组仅取就一个就行,以后再来补补吧。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
inline int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline int Readc() {
char c = getchar();
while (c != 'R' && c != 'F')c = getchar();
if (c == 'F')return 1;
return 0;
}//F能用,E不能用
inline int max(int x, int y) {
return x > y ? x : y;
}
inline int min(int x, int y) {
return x < y ? x : y;
}
//max和min最好自己打
int n, m, ans1, ans, map[2000][2005];;
int g[2005][2005];
int h[2000];
int que[2000];
//向上到达最远的点的距离
int main() {
int t;
cin>>t;
while(t--){
ans = 0;
n = read(), m = read();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
g[i][j]=read();
for (int i = 1; i <= m; i++) {
int len = 1;
for (int j = 2; j <= n; j++) {
if (g[j][i] >= g[j - 1][i]) {
map[j][i] = map[j - 1][i] = len;
} else {
len++;
map[j][i] = 0;
if (j - 1 == 1)map[j - 1][i] = 0;
}
}
}
// for(int i=1;i<=n;i++) {
// for (int j = 1; j <= m; j++) {
// cout << map[i][j] << ' ';
// }
// cout<<endl;
// }
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (i == 1) {
h[j] = 1;
} else if (map[i - 1][j] == map[i][j] && map[i][j] != 0) {
h[j]++;
} else h[j] = 1;
}
int tot = 0;
h[m + 1] = 0;
for (int j = 1; j <= m + 1; j++) {
while (tot && h[que[tot]] > h[j]) {
//cout << (j - que[tot - 1] - 1) * h[que[tot]];
ans = max(ans, (j - que[tot - 1] - 1) * h[que[tot]]);
//printf("%d %d %d\n",j,que[tot-1],h[que[tot]]);
tot--;
//cout<<ans<<' ';
}
que[++tot] = j;
}
}
printf("%d\n", ans);
}
return 0;
}