jzoj5417【NOIP2017提高A组集训10.24】方阵

来源:互联网 发布:彩虹timez知乎 编辑:程序博客网 时间:2024/05/16 05:54

题目

Time Limits: 2000 ms Memory Limits: 262144 KB

Description

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

Input

第一行包含两个整数n,m,表示这个方阵的两条边的长度。
接下来n行,每行m个数,表示每个学生的能力值。
接下来一行包含一个整数q,表示校长的询问数。
接下来q行,每行先一个字符串s,接下来4个整数x1,y1 , x2, y2,保证
x1<=x2,y1<=y2 ,设以第x1行y1列为左上角,第x2行y2列为右下角的方阵为P。(本题为0下标)
若字符串内容为“SUM”,请求出P中所有学生的能力值之和。
若字符串内容为“MAX”,请求出P中所有学生的能力值的最大值。
若字符串内容为“MIN”,请求出P中所有学生的能力值的最小值。

Output

输出总共q行,第i行的数为第i组询问对应的答案ansi

Sample Input

3 3
1 2 3
4 5 6
7 8 9
3
SUM 0 0 1 1
MAX 0 0 2 2
MIN 0 1 1 1

Sample Output

12
9
2

样例说明
对于第一组询问,能力值之和为1+2+4+5=12。
对于第二组询问,能力值最大的位置为第2行第2列。
对于第三组询问,能力值最小的位置为第0行第1列。

Data Constraint

对于40%的数据,n,m<=200,q<=200
对于60%的数据,n,m<=300,q<=100000
对于80%的数据,n,m<=500,q<=500000
对于100%的数据,n,m<=800,q<=500000, 0<=Aij<=3000,

题解

二维rmq直接搞,注意空间和时间都很紧张
对于每一个询问的矩形,用4个rmq中的值就可以求出极值了(四个顶点分别往对应的方向拓展)

贴代码

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=805;short f[maxn][maxn][10][10],g[maxn][maxn][10][10],ans;int sum[maxn][maxn],a[maxn][maxn];int i,j,k,l,n,m,x,y,z,q,t1,t2,t3,t4,o;char s[10],ch;int read(){    int x=0;    ch=getchar();    while (ch<'0' || ch>'9') ch=getchar();    while (ch>='0' && ch<='9'){        x=x*10+ch-48;        ch=getchar();    }    return x;}int main(){    freopen("phalanx.in","r",stdin);    freopen("phalanx.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,n) fo(j,1,m) scanf("%d",&a[i][j]);    fo(i,1,n) fo(j,1,m) sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];    fo(i,1,n) fo(j,1,m){        f[i][j][0][0]=g[i][j][0][0]=a[i][j];        l=0; k=1;        while (k*2<=i){            l++;            f[i][j][l][0]=max(f[i][j][l-1][0],f[i-k][j][l-1][0]);            g[i][j][l][0]=min(g[i][j][l-1][0],g[i-k][j][l-1][0]);            k=k*2;        }    }    fo(i,1,n)         fo(j,1,m){            t1=0; t2=1;            while (t2<=i){                t3=0; t4=1;                while (t4*2<=j){                    t3++;                    f[i][j][t1][t3]=max(f[i][j][t1][t3-1],f[i][j-t4][t1][t3-1]);                    g[i][j][t1][t3]=min(g[i][j][t1][t3-1],g[i][j-t4][t1][t3-1]);                    t4=t4*2;                }                t1++; t2=t2*2;            }        }    scanf("%d",&q);    fo(o,1,q){        scanf("%s",&s);        t1=read(); t2=read(); t3=read(); t4=read(); t1++; t2++; t3++; t4++;        if (s[1]=='U') printf("%d\n",sum[t3][t4]-sum[t1-1][t4]-sum[t3][t2-1]+sum[t1-1][t2-1]); else        if (s[1]=='A'){            ans=0;            x=0; while (t3-(1<<(x+1))+1>=t1) x++;            y=0; while (t4-(1<<(y+1))+1>=t2) y++;            ans=max(f[t3][t4][x][y],f[t1+(1<<x)-1][t2+(1<<y)-1][x][y]);            ans=max(ans,f[t3][t2+(1<<y)-1][x][y]);            ans=max(ans,f[t1+(1<<x)-1][t4][x][y]);            printf("%d\n",ans);        } else        if (s[1]=='I'){            ans=3005;            x=0; while (t3-(1<<(x+1))+1>=t1) x++;            y=0; while (t4-(1<<(y+1))+1>=t2) y++;            ans=min(g[t3][t4][x][y],g[t1+(1<<x)-1][t2+(1<<y)-1][x][y]);            ans=min(ans,g[t3][t2+(1<<y)-1][x][y]);            ans=min(ans,g[t1+(1<<x)-1][t4][x][y]);            printf("%d\n",ans);         }    }    return 0;}