[bzoj1047][HAOI2007]理想的正方形

给定r,c,n和一个r行c列的矩阵,你需要找到一个n*n的矩形,使得其中的最大值和最小值的差最小 r,c<=1000

题解:

看情况乱搞 

线段树先横着查一下每个点后m个的最值,然后竖着搞一遍。

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1024
#define INF 2000000000
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int s[1005][1005],s2[1005][1005];
int T[N*2+5],T2[N*2+5];
int n,m,c,ans=INF;
int num[1005][1005];

int query2(int l,int r)
{
    int sum=INF;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1)sum=min(sum,T2[l+1]);
        if( r&1)sum=min(sum,T2[r-1]);
    }
    return sum;
}

int query1(int l,int r)
{
    int sum=0;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1)sum=max(sum,T[l+1]);
        if( r&1)sum=max(sum,T[r-1]);
    }
    return sum;
}

void renew1(int x,int ad)
{
    T[x+=N]=ad;
    for(x>>=1;x;x>>=1) T[x]=max(T[x<<1],T[(x<<1)+1]);
}

void renew2(int x,int ad)
{
    T2[x+=N]=ad;
    for(x>>=1;x;x>>=1) T2[x]=min(T2[x<<1],T2[(x<<1)+1]);
}

int main()
{
    n=read();m=read();c=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            num[i][j]=read();
    for(int i=1;i<=n;i++)
    {
        memset(T,0,sizeof(T));for(int ii=1;ii<=2*N+1;ii++)T2[ii]=INF;
        for(int j=m;j;j--) 
        {
            renew1(j,num[i][j]);renew2(j,num[i][j]);
            if(j+c-1<=m)
            s[i][j]=query1(j,j+c-1),s2[i][j]=query2(j,j+c-1);    
        }
    }
    //for(int i=1;i<=n;i++) for(int j=1;j+c-1<=m;j++) cout<<i<<" "<<j<<" "<<s[i][j]<<" "<<s2[i][j]<<endl;
    for(int i=1;i+c-1<=m;i++)
    {
        memset(T,0,sizeof(T));for(int ii=1;ii<=2*N+1;ii++)T2[ii]=INF;
        for(int j=n;j;j--)
        {
            renew1(j,s[j][i]);renew2(j,s2[j][i]);
            if(j+c-1<=n) ans=min(ans,query1(j,j+c-1)-query2(j,j+c-1));
        }
    }
    cout<<ans;
    return 0;
}

 

posted @ 2017-03-01 17:10  FallDream  阅读(238)  评论(0编辑  收藏  举报