题目链接:https://ac.nowcoder.com/acm/contest/332/E


思考:只要求二维前缀和(淹没为1,没有淹没为0)对于每次询问,只需要O(1)的时间。

//二维前缀和
//把s[0][i]和s[i][0]全部置为0
//s[i-1][j-1]加重复了,必须减去。
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];

我们可以注意这个数据范围。 数组必须动态申请

//动态申请二维数组
int **a;
a=new int *[n+10];
for(int i=0;i<=n;i++)
{
    a[i]=new int [m+10];
}

还有对每次询问

//对于区间(i, j), (x, y)区间的和
//s[i-1][j-1]减重复了,必须加上。
s[x][y]-s[i-1][y]-s[x][j-1]+s[i-1][j-1]

全部代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//#define p1 first
//#define p2 second
//memset(a, 0, sizeof(a));
//stack堆栈 queue队列 priority_queue优先队列
//vector向量 multiset平衡二叉树 deque双端队列
//pair{T1 first;T2 second;} greater<T>
//unordered_map 哈希map
 
int main()
{
    int n, m, d, q;
    scanf("%d%d%d",&n,&m,&d);
    int **a;
    int **s;
    a=new int *[n+10];
    s=new int *[n+10];
    for(int i=0;i<=n;i++)
    {
        a[i]=new int [m+10];
        s[i]=new int [m+10];
    }
    for(int i=1;i<=n;i++)
    {
        s[i][0]=0;
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
            if(a[i][j]<d)
            {
                a[i][j]=0;
            }
            else
            {
                a[i][j]=1;
            }
        }
    }
    s[0][0]=0;
    for(int i=0;i<=m;i++)
    {
        s[0][i]=0;
    }
    for(int i=1;i<=m;i++)
    {
        s[1][i]=s[1][i-1]+a[1][i];
    }
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];
        }
    }
    scanf("%d",&q);
    while(q--)
    {
        int i, j, x, y;
        scanf("%d%d%d%d",&i,&j,&x,&y);
 
        printf("%d\n",s[x][y]-s[i-1][y]-s[x][j-1]+s[i-1][j-1]);
    }
 
    return 0;
}