【二维st表】【二维单调队列】


【二维st表】【二维单调队列】

修筑绿化带

分析:
首先可以枚举大矩形的右下角,用前缀和算出大矩形的面积和。
接下来考虑快速计算出面积最小的小矩形是多少,可以发现对于一个固定的大矩形,小矩形的右下角的取值范围也构成一个矩形,定义w[i][j]为以(i,j)为右下角,C*D的矩阵的面积和,那么每次我们只需快速求出这个矩形的w的最小值
假设大矩形的右下角为(i,j),则不难推出查询范围:
右下角:(i-1,j-1)
左下角:(i-1,j-B+D+1)
右上角:(i-A+C+1,j-1)
左上角:(i-A+C+1,j-B+D+1)
高:A-C-1
宽:B-D-1
求二维矩形的最值,我们可以类比一维,使用st表预处理。
可以设st[i][j][k][g]表示以(i,j)为左上角,高为\(2^k\),长为\(2^g\)的矩形中的最小值,则k,g为阶段,先预处理st[i][j][0][0],再计算st[i][j][0][g],st[i][j][k][0],在计算st[i][j][k][g]即可。
询问用4个矩形拼凑即可

核心代码

void stpre()
{
	for(int i=2;i<=max(n,m);++i) mxlg[i]=((1<

但是这样空间会炸(时间可以接受),发现在查询的时候高和宽都是固定的,所以没必要保存那么多次幂的情况,只需保存用到的即可,计算时滚动即可

核心代码

void stpre()
{
	for(int i=2;i<=max(n,m);++i) mxlg[i]=((1<

但是既然都发现查询的矩形形状是固定的了,干嘛还用st表呢?考虑我们在一维状态下,如果查询区间固定的话,可以用单调队列线性计算,二维同理。
先用单调队列对每个点求出从这个点往上h个单位(h为查询矩形的高)中的最小值up[i][j],在用类似的方法横着做一遍单调队列,就能算出以(i,j)为右下角的矩形的最小值wd[i][j]

代码:

for(int j=1;j<=m;++j)
{
	l=1,r=0;
	for(int i=1;i<=a;++i)
	{
		while(l<=r&&w[q[r]][j]>=w[i][j])r--;
		q[++r]=i;
	}
	up[a][j]=w[q[l]][j];
	for(int i=a+1;i<=n;++i)
	{
		while(l<=r&&w[q[r]][j]>=w[i][j]) r--;
		q[++r]=i;
		if(q[l]==i-a) l++;
		up[i][j]=w[q[l]][j];
	}
}
for(int i=a;i<=n;++i)
{
	l=1,r=0;
	for(int j=1;j<=b;++j)
	{
		while(l<=r&&up[i][q[r]]>=up[i][j]) r--;
		q[++r]=j;
	}
	wd[i][b]=up[i][q[l]];
	for(int j=b+1;j<=m;++j)
	{
		while(l<=r&&up[i][q[r]]>=up[i][j]) r--;
		q[++r]=j;
		if(q[l]==j-b) l++;
		wd[i][j]=up[i][q[l]];
	}
}