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 <script type="math/tex" id="MathJax-Element-206">8</script>个正方形便可以覆盖掉。

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]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值