JZOJ 5417 方阵

方阵

Description

给出一个n*m的矩形A,第i行第j列的值为Ai,j
给出q个询问,每次询问某个在A内的矩阵的最大值,最小值以及和。

Data Constraint

n,m<=800,q<=500000,0<=Ai,j<=3000,每个询问的方阵的长不超过宽的两倍

Solution

方法一
一看到这题直接上二维RMQ,但这样不仅会空间超限,预处理还会时间超限。
既然会空间超限,那就可以预处理少一点,只预处理到27,这样预处理空间时间都不会超限,同时询问的时候最多也只需用49个预处理好的RMQ平面来覆盖,整体时间复杂度控制在了可以过掉的范围内。

方法二
看到每个询问的方阵的长不超过宽的两倍,于是便可以只预处理以某个位置为右下角的边长为2k的正方形内的信息,这样一来一个方阵用8个正方形便可以覆盖掉。

Code(Solution 1)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define fo(i,j,l) for(int i=j;i<=l;i++)
#define fd(i,j,l) for(int i=j;i>=l;i--)
#define mm 'M'
#define xx 'X'
#define nn 'N'


using namespace std;
typedef long long ll;
const ll N=802,P=8,M=51e4;
int n,m,j,k,l,i,o,qq;
int a[N][N],q[N][N],f[N][N][P][P],xw[M][4],ans[M],m2[10],bl[N];
int d1[2*P],d2[2*P];
char c[M];

int read()
{
    int a=0; char ch=' ';
    for(;ch<'0'||ch>'9';)ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar())a=a*10+ch-48;
    return a;
}

int min(int a,int b)
{if(a<b)return a;else return b;}
int max(int a,int b)
{if(a>b)return a;else return b;}

void pri(int o)
{if(!o)return; pri(o/10); putchar('0'+o%10);}
void write(int o)
{
    if(o>0)pri(o);else putchar('0'); 
    putchar('\n');
}

int main()
{
    cin>>n>>m;
    fo(i,1,n)fo(l,1,m)a[i][l]=read(),q[i][l]=q[i][l-1]+a[i][l];
    fo(i,1,n)fo(l,1,m)q[i][l]+=q[i-1][l];
    m2[0]=1; fo(i,1,9)m2[i]=m2[i-1]*2;
    for(int k=0,i=1;i<=max(n,m);i++){
        bl[i]=k;
        if(i==m2[k]*2)k=min(k+1,P-1);
    }
    fo(i,1,n){
        fo(l,1,m)f[i][l][0][0]=a[i][l];
        fo(j,1,bl[m])
        fo(l,1,m-m2[j]+1)
        f[i][l][0][j]=min(f[i][l][0][j-1],f[i][l+m2[j-1]][0][j-1]);
    }
    fo(j,1,bl[n])
    fo(i,1,n-m2[j]+1)
    fo(k,0,bl[m])
    fo(l,1,m-m2[k]+1)
    f[i][l][j][k]=min(f[i][l][j-1][k],f[i+m2[j-1]][l][j-1][k]);
    cin>>qq;
    fo(i,1,qq){
        for(c[i]='\n';c[i]=='\n';)c[i]=getchar();
        c[i]=getchar(); c[i]=getchar();
        xw[i][0]=read()+1,xw[i][1]=read()+1;
        xw[i][2]=read()+1,xw[i][3]=read()+1;
        if(c[i]==mm){
            int x1=xw[i][0]-1,x2=xw[i][2],y1=xw[i][1]-1,y2=xw[i][3];
            ans[i]=q[x2][y2]-q[x2][y1]-q[x1][y2]+q[x1][y1];
        }
        if(c[i]==nn)
        {
            ans[i]=q[n][m];
            int x1=xw[i][0],x2=xw[i][2],y1=xw[i][1],y2=xw[i][3];
            int r1=1,r2=1,o1=bl[x2-x1+1],o2=bl[y2-y1+1];
            for(d1[1]=x1;d1[r1]+m2[o1]-1<x2;r1++)d1[r1+1]=d1[r1]+m2[o1];
            d1[r1]=x2-m2[o1]+1;
            for(d2[1]=y1;d2[r2]+m2[o2]-1<y2;r2++)d2[r2+1]=d2[r2]+m2[o2];
            d2[r2]=y2-m2[o2]+1;
            fo(l,1,r1)fo(j,1,r2)
            ans[i]=min(ans[i],f[d1[l]][d2[j]][o1][o2]);
        }
    }
    fo(i,1,n){
        fo(l,1,m)f[i][l][0][0]=a[i][l];
        fo(j,1,bl[m])
        fo(l,1,m-m2[j]+1)
        f[i][l][0][j]=max(f[i][l][0][j-1],f[i][l+m2[j-1]][0][j-1]);
    }
    fo(j,1,bl[n])
    fo(i,1,n-m2[j]+1)
    fo(k,0,bl[m])
    fo(l,1,m-m2[k]+1)
    f[i][l][j][k]=max(f[i][l][j-1][k],f[i+m2[j-1]][l][j-1][k]);
    fo(i,1,qq)if(c[i]==xx)
    {
        ans[i]=0;
        int x1=xw[i][0],x2=xw[i][2],y1=xw[i][1],y2=xw[i][3];
        int r1=1,r2=1,o1=bl[x2-x1+1],o2=bl[y2-y1+1];
        for(d1[1]=x1;d1[r1]+m2[o1]-1<x2;r1++)d1[r1+1]=d1[r1]+m2[o1];
        d1[r1]=x2-m2[o1]+1;
        for(d2[1]=y1;d2[r2]+m2[o2]-1<y2;r2++)d2[r2+1]=d2[r2]+m2[o2];
        d2[r2]=y2-m2[o2]+1;
        fo(l,1,r1)fo(j,1,r2)
        ans[i]=max(ans[i],f[d1[l]][d2[j]][o1][o2]);
    }
    fo(i,1,qq)write(ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值