洛谷p2216 多次单调队列,扫描矩阵中的最大值减去最小值最的固定大小子矩阵

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int a,b,n;
int m[1005][1005],q[7][1005][2005];
int head[7][1005],tail[7][1005],l[5][1005],r[3][1005];
int main(){
    while(~scanf("%d%d%d",&a,&b,&n)){
        int i,j,k;
        for(i=1;i<=a;++i){
            for(j=1;j<=b;++j){
                scanf("%d",&m[i][j]);
            }
        }
        for(i=1;i<=b;++i) {
            l[2][i]=r[2][i]=1;
        }
        memset(head,0,sizeof(head));
        memset(tail,0,sizeof(tail));
        int ans=~(0u)>>1;
        for(i=1;i<=a-n+1;++i){
            int row=i;
            l[1][i]=r[1][i]=1;
            while(r[1][i]<=b){
                    while(r[1][i]-l[1][i]+1<=n){
                        int col=r[1][i];
                        while(r[2][col]-l[2][col]+1<=n){
                            int t=r[2][col];
                            while(head[3][col]!=tail[3][col]&&m[q[3][col][tail[3][col]-1]][col]<=m[t][col]) tail[3][col]--;
                            q[3][col][tail[3][col]++]=t;
                            while(head[4][col]!=tail[4][col]&&m[q[4][col][tail[4][col]-1]][col]>=m[t][col]) tail[4][col]--;
                            q[4][col][tail[4][col]++]=t;
                            r[2][col]++;
                        }
                        while(head[1][row]!=tail[1][row]&&head[5][row]!=tail[5][row]&&m[q[5][row][tail[5][row]-1]][q[1][row][tail[1][row]-1]]<=m[q[3][col][head[3][col]]][col]) 
                        {

                                tail[1][row]--,tail[5][row]--;    
                        }
                        q[1][row][tail[1][row]++]=col,q[5][row][tail[5][row]++]=q[3][col][head[3][col]];
                        while(head[2][row]!=tail[2][row]&&head[6][row]!=tail[6][row]&&m[q[6][row][tail[6][row]-1]][q[2][row][tail[2][row]-1]]>=m[q[4][col][head[4][col]]][col]) 
                        {
                                tail[2][row]--,tail[6][row]--;
                        }
                        q[2][row][tail[2][row]++]=col,q[6][row][tail[6][row]++]=q[4][col][head[4][col]];
                        l[2][col]++;
                        while(head[3][col]!=tail[3][col]&&q[3][col][head[3][col]]<l[2][col]) head[3][col]++;
                        while(head[4][col]!=tail[4][col]&&q[4][col][head[4][col]]<l[2][col]) head[4][col]++;
                        r[1][i]++;
                }
                ans=min(ans,m[q[5][row][head[5][row]]][q[1][row][head[1][row]]]-m[q[6][row][head[6][row]]][q[2][row][head[2][row]]]);
                l[1][i]++;
                while(head[1][row]!=tail[1][row]&&q[1][row][head[1][row]]<l[1][i]) head[1][row]++,head[5][row]++;
                while(head[2][row]!=tail[2][row]&&q[2][row][head[2][row]]<l[1][i]) head[2][row]++,head[6][row]++;        
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

竖着跑一遍单调队列,跑完竖的所有列,再对所有列的最值跑一遍行的

posted @ 2017-03-18 16:17  狡啮之仰  阅读(515)  评论(0编辑  收藏  举报