码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 1047

时间:2017-10-23 20:07:55      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:sdi   问题   队列   print   read   logs   +=   nbsp   ace   

枚举右下角,问题转化成求以(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

标签:sdi   问题   队列   print   read   logs   +=   nbsp   ace   

原文地址:http://www.cnblogs.com/oris71/p/7718534.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!