【二维单调队列】FZU- Problem 2080 最大差值

题意:给出一个n*m的矩阵,要求求出它所有r*c子矩阵里面的元素的最大值减最小值的差的最大值。

思路:二维的单调队列维护,时间复杂度为O(n^2)。

题目

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
#define N 1005
int head,tail,mat[N][N],vmax[N][N],vmin[N][N];          //vmax[i][j]表示(i,j)到(i+d-1,j+d-1)中的最大值,vmin[i][j]表示(i,j)到(i+d-1,j+d-1)中的最小值。
struct node
{
    int num,id;
};
node que[N];
void add_max(int num,int id)
{
    while(head<tail&&que[tail-1].num<=num)tail--;          //单调队列维护
    que[tail].id=id;
    que[tail++].num=num;
}
void add_min(int num,int id)
{
    while(head<tail&&que[tail-1].num>=num)tail--;
    que[tail].id=id;
    que[tail++].num=num;
}
int get_num(int id)
{
    while(head<tail&&que[head].id<id)head++;
    return que[head].num;
}
int main()
{
    //freopen("a.txt","r",stdin);
    int n,m,r,c;
    while(scanf("%d%d%d%d",&n,&m,&r,&c)!=EOF)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                scanf("%d",&mat[i][j]);
            }
        }
        for(int i=0;i<m;i++)
        {
            head=tail=0;
            for(int j=0;j<r-1;j++)add_max(mat[j][i],j);
            for(int j=r-1;j<n;j++)
            {
                add_max(mat[j][i],j);
                vmax[j-r+1][i]=get_num(j-r+1);          //这时的vmax[j-r+1][i]表示第i列中的第j-r+1行到第j行的最大值
            }
        }
        for(int i=0;i<=n-r;i++)
        {
            head=tail=0;
            for(int j=0;j<c-1;j++)add_max(vmax[i][j],j);          //这里就是二维单调队列维护了
            for(int j=c-1;j<m;j++)
            {
                add_max(vmax[i][j],j);
                vmax[i][j-c+1]=get_num(j-c+1);
            }
        }
        for(int i=0;i<m;i++)
        {
            head=tail=0;
            for(int j=0;j<r-1;j++)add_min(mat[j][i],j);
            for(int j=r-1;j<n;j++)
            {
                add_min(mat[j][i],j);
                vmin[j-r+1][i]=get_num(j-r+1);
            }
        }
        for(int i=0;i<=n-r;i++)
        {
            head=tail=0;
            for(int j=0;j<c-1;j++)add_min(vmin[i][j],j);
            for(int j=c-1;j<m;j++)
            {
                add_min(vmin[i][j],j);
                vmin[i][j-c+1]=get_num(j-c+1);
            }
        }
        int ans=0;
        for(int i=0;i<=n-r;i++)
        {
            for(int j=0;j<=m-c;j++)
            {
                ans=max(ans,vmax[i][j]-vmin[i][j]);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值