单调栈可以维护一个长度递增的序列,当新加入的元素不递增时,会把前面的元素截断,使其保持递增
由于截断之后大量的元素长度相同,所以没有必要把所有所有元素压入栈,只需将这些元素压缩成一个(用矩阵块和表示!),记录个数,放入栈既可。
//#pragma comment(linker, "/STACK:102400000")
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<vector>
#define tree int o,int l,int r
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lo o<<1
#define ro o<<1|1
#define ULL unsigned long long
#define LL long long
#define inf 0x7fffffff
#define eps 1e-7
#define N 3009
using namespace std;
int m,n,T,t,x,y,k;
LL a[N][N],sum[N][N];
LL q[N],top,len[N],d[N];
LL sumhe(int x,int y,int a,int b)
{
return sum[x][y]-sum[a][y]-sum[x][b]+sum[a][b];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ex.in","r",stdin);
#endif
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; ++j)
{
scanf("%I64d",&a[i][j]);
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
memset(len,0,sizeof(len));
LL ans=0;
for(int i=1; i<=n; i++)
{
top=0;
d[0]=0;
q[top++]=0;
for(int j=1; j<=m; ++j)
{
if(a[i][j]>=k)len[j]++;
else len[j]=0;
while(top>0&&len[j]<len[q[top-1]])
top--;
int pre=q[top-1];
if(len[j]==0)
d[j]=0;
else
d[j]=d[pre]+sumhe(i,j,i-len[j],pre);
ans=max(ans,d[j]);
q[top++]=j;
}
}
printf("%I64d\n",ans);
}
return 0;
}