【JZOJ5417】方阵

Description

题目背景
热烈庆祝北京师范大学附属实验中学成立100周年!
问题描述
为了准备校庆庆典,学校招募了一些学生组成了一个方阵,准备在庆典上演出。
这个方阵是一个n*m的矩形,第i行第j列有一名学生,他有一个能力值Aij。
校长会定期检查一个p*q的方阵,询问这个方阵的学生能力值之和,或是学生能力值的最大值,或是学生能力值的最小值。由于校长不喜欢一个方阵长宽之比差太多,他每次询问的方阵的长不会超过宽的两倍。作为校庆筹办组组长的你,应该迅速并准确的回答校长所问的问题。

Solution

通常做法是二维rmq,当然二维线段树也是可以的。

但rmq通常是4维的,这题空间不够,于是可以省去一维,只记录正方形,因为题目的数据保证(然而不保证)可以由至多8个正方形拼起来。

当然可以像原来那样设4维,开小空间,然后一个矩形就用64个rmq矩形拼起来。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 810
#define inf 2147483647
using namespace std;
void read(int &n){
    char ch=' ';int t=0,c=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-') c=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar()) t=t*10+ch-48;n=t*c;
}
int rmx[10][N][N],rmn[10][N][N];
int a[N][N],s[N][N];
int lg[N],mi[N];
int max(int x,int y){
    return x>y?x:y;
}
int min(int x,int y){
    return x<y?x:y;
}
int n,m;
int max4(int x1,int x2,int x3,int x4){
    return max(x1,max(x2,max(x3,x4)));
}
int min4(int x1,int x2,int x3,int x4){
    return min(x1,min(x2,min(x3,x4)));
}
int rmax(int x1,int y1,int x2,int y2){
    int t=lg[min(x2-x1+1,y2-y1+1)],tt=1<<t;
    int tmp=0;
    bool tag=0;
    int p=x1;
    fo(i,1,n){
        if(p+tt-1>x2) p=x2-tt+1,tag=1;
        int q=y1;
        fo(j,1,m){
            if(q+tt>y2) {tmp=max(tmp,rmx[t][p][y2-tt+1]);break;}
            tmp=max(tmp,rmx[t][p][q]),q+=tt;
        }
        if(tag) break;
        p+=tt;
    }
    return tmp;
}
int rmin(int x1,int y1,int x2,int y2){
    int t=lg[min(x2-x1+1,y2-y1+1)],tt=1<<t;
    int tmp=inf;
    bool tag=0;
    int p=x1;
    fo(i,1,n){
        if(p+tt-1>x2) p=x2-tt+1,tag=1;
        int q=y1;
        fo(j,1,m){
            if(q+tt>y2) {tmp=min(tmp,rmn[t][p][y2-tt+1]);break;}
            tmp=min(tmp,rmn[t][p][q]),q+=tt;
        }
        if(tag) break;
        p+=tt;
    }
    return tmp;
}
void pre()
{
    int mx=max(n,m);
    lg[1]=0,lg[2]=1,mi[0]=1;
    fo(i,3,mx){
        lg[i]=lg[i-1];
        if((1<<lg[i]+1)<=i) lg[i]++;
    }
    fo(i,1,9) mi[i]=mi[i-1]*2;
    fo(k,1,lg[mx])
    fo(i,1,n) if(i+(1<<k)-1<=n)
    fo(j,1,m) if(j+(1<<k)-1<=m)
    {
        int t=1<<k-1;
        rmx[k][i][j]=max4(rmx[k-1][i][j],rmx[k-1][i+t][j],rmx[k-1][i][j+t],rmx[k-1][i+t][j+t]);
        rmn[k][i][j]=min4(rmn[k-1][i][j],rmn[k-1][i+t][j],rmn[k-1][i][j+t],rmn[k-1][i+t][j+t]);
    }
}
int main()
{
    freopen("phalanx.in","r",stdin);
    freopen("phalanx.out","w",stdout);
    read(n),read(m);
    fo(i,1,n)
    fo(j,1,m)
    {
        read(a[i][j]);
        s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
        rmx[0][i][j]=rmn[0][i][j]=a[i][j];
    }
    pre();
    int q;
    read(q);
    while(q--)
    {
        char S[4];
        scanf("%s",S);
        int x1,y1,x2,y2;
        read(x1),read(y1),read(x2),read(y2);
        x1++,y1++,x2++,y2++;
        if(S[1]=='U') printf("%d\n",s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
        else if(S[1]=='A') printf("%d\n",rmax(x1,y1,x2,y2));
        else printf("%d\n",rmin(x1,y1,x2,y2));
    }
}
posted @ 2017-10-24 21:41  sadstone  阅读(52)  评论(0编辑  收藏  举报