HDU 6514 2019中山大学程序设计竞赛(二维前缀和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6514

 

题目大意:给出p个矩阵,q次查询,问查询的矩阵中是否有点不存在于这p个矩阵中

 

题目思路:二维前缀和模板题,对于添加一个矩阵(x1,y1,x2,y2),需要a[x1][y1]+1(黄),a[x2+1][y]-1(红+黄),a[x1][y2+1]-1(深红+黄),由于右上角被删了两次,所以需要再a[x2+1][y2+1]+1。HDU 6514 2019中山大学程序设计竞赛(二维前缀和)_第1张图片

然后现在矩阵处理下前缀和,来获得每个点被多少个矩阵覆盖过。计算的方法是a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1](根据刚才的方法理解),然后将>1的变成1,接着再处理前缀和,查询的时候就是a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1],如果等于(x2-x1+1)*(y2-y1+1),那么就说明每个点都被覆盖过,那么就是yes,否则就是no。由于数据范围是n*m<=1e7,所以需要把二维数组拍扁成一维,用i*m+j即可。

 

以下是代码:

#include
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const int MAXN = 1e7+5;
const int MOD = 998244353;
int n,m,q,x,y,xx,yy;
int a[MAXN];
int getid(int i,int j){
    return i*m+j;
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        memset(a,0,sizeof(a));
        scanf("%d",&q);
        while(q--){
            scanf("%d%d%d%d",&x,&y,&xx,&yy);
            a[getid(x,y)]++;
            a[getid(xx+1,y)]--;
            a[getid(x,yy+1)]--;
            a[getid(xx+1,yy+1)]++;
        }

        rep(i,1,n){
            rep(j,1,m){
                a[getid(i,j)]+=a[getid(i-1,j)]+a[getid(i,j-1)]-a[getid(i-1,j-1)];
            }
        }
        rep(i,1,n){
            rep(j,1,m){
                a[getid(i,j)]=(a[getid(i,j)]>0);
            }
        }
        rep(i,1,n){
            rep(j,1,m){
                a[getid(i,j)]+=a[getid(i-1,j)]+a[getid(i,j-1)]-a[getid(i-1,j-1)];
            }
        }
        scanf("%d",&q);
        while(q--){
            scanf("%d%d%d%d",&x,&y,&xx,&yy);
            if(a[getid(xx,yy)]-a[getid(xx,y-1)]-a[getid(x-1,yy)]+a[getid(x-1,y-1)]==(xx-x+1)*(yy-y+1)){
                puts("YES");
            }
            else{
                puts("NO");
            }
        }
    }
    return 0;
}

 

你可能感兴趣的:(前缀和)