首页 > 代码库 > 洛谷OJ 2216 理想的正方形 单调队列(二维)

洛谷OJ 2216 理想的正方形 单调队列(二维)

https://www.luogu.org/problem/show?pid=2216

题意:给出a*b矩形 从中找到一个n*n正方形,其(最大值-最小值之差)最小,a,b<=1e3,n<=100
暴力枚举正方形右下角,如何快速算出其最大值和最小值?
先用单调队列预处理出ma[i][j] 表示(i,j)以第i行j列结尾长度为n的最大值
/在枚举列之后,对同一个列,由于已经知道该列 每行长度为n的最值 则在次利用单调队列,从上往下扫描行,求出(i,j)为右下角的矩形的最值即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=9999973;
const int N=2e3+20;
int c[N][N],a,b,n;
int ma[N][N],mi[N][N],q[N],d[N];

void init()
{
    //l=r队列为空 r指向最后一个元素的下一个 
    for(int i=1;i<=a;i++)
    {
        int l=1,r=1;
        for(int j=1;j<=b;j++)
        {
            while(l<r&&j-d[l]>=n) l++;//淘汰过时元素 
            while(l<r&&q[r-1]<=c[i][j]) r--;//保持单调  
            
            d[r]=j;//记录下标 
            q[r++]=c[i][j];
                
            if(j>=n)
                ma[i][j]=q[l];
        }
        memset(d,0,sizeof(d));
        l=1,r=1;
        for(int j=1;j<=b;j++)
        {
            while(l<r&&j-d[l]>=n) l++;//
            while(l<r&&q[r-1]>=c[i][j]) r--;
            
            d[r]=j;
            q[r++]=c[i][j];
            if(j>=n)
                mi[i][j]=q[l];
        }    
    }
}
int tx[N],ti[N];
void calc()
{
    int ans=1e9;
    for(int j=n;j<=b;j++)//固定列 
    { 
        int l=0,r=0;
        for(int i=1;i<=a;i++)//右下角坐标 
        {
            while(l<r&&q[r-1]<=ma[i][j]) r--;//预处理每行的长度为n中的最值后->相当于降维 
            while(l<r&&i-d[l]>=n) l++;
            
            q[r]=ma[i][j],d[r++]=i;
            if(i>=n)    
                tx[i]=q[l];//(固定列后 右下角为(i,j)的正方形的最值)
        }
        memset(d,0,sizeof(d));
        l=0,r=0;
        for(int i=1;i<=a;i++)
        {
            while(l<r&&q[r-1]>=mi[i][j]) r--;
            while(l<r&&i-d[l]>=n) l++;
            
            q[r]=mi[i][j],d[r++]=i;
            if(i>=n)
                ti[i]=q[l];
        }
        
        
        for(int k=n;k<=a;k++)
            ans=min(ans,tx[k]-ti[k]);
    }
    cout<<ans<<endl;
}
int main()
{
    while(cin>>a>>b>>n)
    {
        for(int i=1;i<=a;i++)
            for(int j=1;j<=b;j++)
                cin>>c[i][j];
        init();
        calc();
    }
        return 0;
} 

 

洛谷OJ 2216 理想的正方形 单调队列(二维)