1. 程式人生 > >[2017紀中10-24]方陣 二維ST表

[2017紀中10-24]方陣 二維ST表

題面
假的資料。。。考場上被坑成0分。
首先兩個log的二維ST表很好想,st[i][j][k][l]表示以點(i,j)向右2^k,向下2^l的矩形內的答案。
(假設)考慮真的長不超過寬的兩倍,我們可以把它分成兩個以寬為邊長的正方形(當然可能會有部分重疊),那麼詢問都轉化成正方形,只需要預處理st[i][j][k]表示以點(i,j)向右下2^k的正方形內的答案。時間和空間都少了一個log。
原版程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define chkmin(a,b) a=min(a,b) #define chkmax(a,b) a=max(a,b) using namespace std; int n,m,w,q,a[810][810],mx[810][810][11],mi[810][810][11]; long long sum[810][810]; int qmx(int x1,int y1,int x2,int y2,int k) { int t=(int)(log(k)/log(2)),r=(1<<t); return max(max(mx[x1][y1][t],mx[x2-r+1][y2-r+1
][t]),max(mx[x2-r+1][y1][t],mx[x1][y2-r+1][t])); } int qmi(int x1,int y1,int x2,int y2,int k) { int t=(int)(log(k)/log(2)),r=(1<<t); return min(min(mi[x1][y1][t],mi[x2-r+1][y2-r+1][t]),min(mi[x2-r+1][y1][t],mi[x1][y2-r+1][t])); } int main() { freopen("phalanx.in","r",stdin); freopen("phalanx.out"
,"w",stdout); scanf("%d%d",&n,&m); w=min(n,m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); memset(mi,0x3f,sizeof(mi)); memset(mx,0,sizeof(mx)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]; mx[i][j][0]=mi[i][j][0]=a[i][j]; } for(int k=1;(1<<k)<=w;k++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { mx[i][j][k]=mx[i][j][k-1]; if(i+(1<<(k-1))<=n) chkmax(mx[i][j][k],mx[i+(1<<(k-1))][j][k-1]); if(j+(1<<(k-1))<=m) chkmax(mx[i][j][k],mx[i][j+(1<<(k-1))][k-1]); if(i+(1<<(k-1))<=n&&j+(1<<(k-1))<=m) chkmax(mx[i][j][k],mx[i+(1<<(k-1))][j+(1<<(k-1))][k-1]); } for(int k=1;(1<<k)<=w;k++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { mi[i][j][k]=mi[i][j][k-1]; if(i+(1<<(k-1))<=n) chkmin(mi[i][j][k],mi[i+(1<<(k-1))][j][k-1]); if(j+(1<<(k-1))<=m) chkmin(mi[i][j][k],mi[i][j+(1<<(k-1))][k-1]); if(i+(1<<(k-1))<=n&&j+(1<<(k-1))<=m) chkmin(mi[i][j][k],mi[i+(1<<(k-1))][j+(1<<(k-1))][k-1]); } scanf("%d",&q); for(int i=1;i<=q;i++) { char opt[3]; int x1,y1,x2,y2,k; scanf("%s",opt); scanf("%d%d%d%d",&x1,&y1,&x2,&y2);x1++;y1++;x2++;y2++; k=min(x2-x1,y2-y1); if(opt[1]=='U') {printf("%lld\n",sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]);continue;} if(opt[1]=='A') {printf("%d\n",max(qmx(x1,y1,x1+k,y1+k,k+1),qmx(x2-k,y2-k,x2,y2,k+1)));} if(opt[1]=='I') {printf("%d\n",min(qmi(x1,y1,x1+k,y1+k,k+1),qmi(x2-k,y2-k,x2,y2,k+1)));} } return 0; }

但因為資料的原因,要把它分成多個正方形,於是寫一個迴圈來分。
迴圈版程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define chkmin(a,b) a=min(a,b)
#define chkmax(a,b) a=max(a,b)
using namespace std;
int n,m,w,q,a[810][810],mx[810][810][11],mi[810][810][11];
long long sum[810][810];
int qmx(int x1,int y1,int x2,int y2,int k)
{
    int t=(int)(log(k)/log(2)),r=(1<<t);
    return max(max(mx[x1][y1][t],mx[x2-r+1][y2-r+1][t]),max(mx[x2-r+1][y1][t],mx[x1][y2-r+1][t]));
}
int qmi(int x1,int y1,int x2,int y2,int k)
{
    int t=(int)(log(k)/log(2)),r=(1<<t); 
    return min(min(mi[x1][y1][t],mi[x2-r+1][y2-r+1][t]),min(mi[x2-r+1][y1][t],mi[x1][y2-r+1][t]));
}
int spmx(int x1,int y1,int x2,int y2,int k)
{
    int re=0;
    if(x1+k==x2)
    {
        for(int t=1;y1+k<y2;t++,y1+=k+1) chkmax(re,qmx(x1,y1,x2,y1+k,k+1));
        chkmax(re,qmx(x1,y2-k,x2,y2,k+1));
    }
    else
    {
        for(int t=1;x1+k<x2;t++,x1+=k+1) chkmax(re,qmx(x1,y1,x1+k,y2,k+1));
        chkmax(re,qmx(x2-k,y1,x2,y2,k+1));
    }
    return re;
}
int spmi(int x1,int y1,int x2,int y2,int k)
{
    int re=1e9;
    if(x1+k==x2)
    {
        for(int t=1;y1+k<y2;t++,y1+=k+1) chkmin(re,qmi(x1,y1,x2,y1+k,k+1));
        chkmin(re,qmi(x1,y2-k,x2,y2,k+1));
    }
    else
    {
        for(int t=1;x1+k<x2;t++,x1+=k+1) chkmin(re,qmi(x1,y1,x1+k,y2,k+1));
        chkmin(re,qmi(x2-k,y1,x2,y2,k+1));
    }
    return re;
}
int main()
{
    freopen("phalanx.in","r",stdin);
    freopen("phalanx.out","w",stdout);
    scanf("%d%d",&n,&m);
    w=min(n,m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    memset(mi,0x3f,sizeof(mi));
    memset(mx,0,sizeof(mx));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
            mx[i][j][0]=mi[i][j][0]=a[i][j];
        }
    for(int k=1;(1<<k)<=w;k++)      
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                {
                    mx[i][j][k]=mx[i][j][k-1];
                    if(i+(1<<(k-1))<=n) chkmax(mx[i][j][k],mx[i+(1<<(k-1))][j][k-1]);
                    if(j+(1<<(k-1))<=m) chkmax(mx[i][j][k],mx[i][j+(1<<(k-1))][k-1]);
                    if(i+(1<<(k-1))<=n&&j+(1<<(k-1))<=m)    chkmax(mx[i][j][k],mx[i+(1<<(k-1))][j+(1<<(k-1))][k-1]);
                }
    for(int k=1;(1<<k)<=w;k++)      
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                {
                    mi[i][j][k]=mi[i][j][k-1];
                    if(i+(1<<(k-1))<=n) chkmin(mi[i][j][k],mi[i+(1<<(k-1))][j][k-1]);
                    if(j+(1<<(k-1))<=m) chkmin(mi[i][j][k],mi[i][j+(1<<(k-1))][k-1]);
                    if(i+(1<<(k-1))<=n&&j+(1<<(k-1))<=m)    chkmin(mi[i][j][k],mi[i+(1<<(k-1))][j+(1<<(k-1))][k-1]);
                }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        char opt[3];
        int x1,y1,x2,y2,k;
        scanf("%s",opt);
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);x1++;y1++;x2++;y2++;
        k=min(x2-x1,y2-y1);
        if(opt[1]=='U') {printf("%lld\n",sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]);continue;}
        if(opt[1]=='A') {printf("%d\n",spmx(x1,y1,x2,y2,k));}
        if(opt[1]=='I') {printf("%d\n",spmi(x1,y1,x2,y2,k));}
    }
    return 0;
}