1. 程式人生 > >bzoj 1047

bzoj 1047

min n) += std namespace 理解 clu name 右下角

枚舉右下角,問題轉化成求以(x,y)為右下角的n*n正方形中的極值。

我們可以先把這個n*n正方形拆成n行n列。

用單調隊列可以很快求出每一個位置往左n個的極值。

然後存儲下來再用單調隊列再求一次,合起來就是一個n*n正方形。

感覺很難說清楚,可以配合代碼理解。

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
int read(){
    char c; while(!isdigit(c=getchar())); int x=c-
0; while(isdigit(c=getchar())) x=x*10+c-0; return x; } int m[1001][1001],_1[1001][1001],_2[1001][1001],q1[1001],q2[1001]; int main(){ int a=read(),b=read(),n=read(),ans=2e9; for(int i=1;i<=a;i+=1) for(int j=1;j<=b;j+=1) m[i][j]=read(); for(int i=1;i<=a;i+=1){ int h1=0
,t1=0,h2=0,t2=0; for(int j=1;j<=b;j+=1){ while(h1<t1 && q1[h1]<=j-n) h1++; while(h2<t2 && q2[h2]<=j-n) h2++; while(h1<t1 && m[i][j]<=m[i][q1[t1-1]]) t1--; q1[t1++]=j; while(h2<t2 && m[i][j]>=m[i][q2[t2-1
]]) t2--; q2[t2++]=j; _1[i][j]=m[i][q1[h1]]; _2[i][j]=m[i][q2[h2]]; } } for(int j=n;j<=b;j+=1){ int h1=0,t1=0,h2=0,t2=0; for(int i=1;i<=a;i+=1){ while(h1<t1 && q1[h1]<=i-n) h1++; while(h2<t2 && q2[h2]<=i-n) h2++; while(h1<t1 && _1[i][j]<=_1[q1[t1-1]][j]) t1--; q1[t1++]=i; while(h2<t2 && _2[i][j]>=_2[q2[t2-1]][j]) t2--; q2[t2++]=i; if(i>=n) ans=min(_2[q2[h2]][j]-_1[q1[h1]][j],ans); } } printf("%d",ans); return 0; }

bzoj 1047