题意:有一个 n*m 的矩阵田地,现在安装 p 个摄像头,每个摄像头都会监视一个矩形的区域,然后现在有若干伙作案团伙回来偷菜,他们偷菜的区域也是一块矩形区域,现在问你,p 个摄像头能不能完全把这块被偷的区域监视到;
分析:二维差分;
代码:
#include<cstdio>
#include<iostream>
using namespace std;
inline void read(int &x){
x=0;char c=getchar();
while(!isdigit(c)){c=getchar();}
while(isdigit(c)){x=(x<<3)+(x<<1)+(c-48);c=getchar();}
}
const int N = 2E7+10;
int s[N]; //因为 n*m<=1E7,可以开vector二维,这里选择开一维模拟
int n,m,p,q;
int id(int x,int y){return m*x+y;}
void add(int x,int y,int op){s[id(x,y)]+=op;}
int sum(int x1,int y1,int x2,int y2){
return s[id(x2,y2)]-s[id(x2,y1-1)]-s[id(x1-1,y2)]+s[id(x1-1,y1-1)];
//二维前缀和查询
}
int main()
{
while(~scanf("%d%d",&n,&m)){
for(int i=0;i<=(n+1)*(m+1);i++) s[i]=0;
read(p);
while(p--){
int x1,y1,x2,y2;
read(x1),read(y1),read(x2),read(y2);
//这四句是二维差分基本语句,就不解释了
add(x1,y1,1);
add(x1,y2+1,-1);
add(x2+1,y1,-1);
add(x2+1,y2+1,1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[id(i,j)]+=s[id(i-1,j)]+s[id(i,j-1)]-s[id(i-1,j-1)];
//第一遍前缀和是根据差分的性质求出每个点被几个摄像头监视到;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[id(i,j)]>1) s[id(i,j)]=1;
//只要被监视到,置 1 ;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[id(i,j)]+=s[id(i-1,j)]+s[id(i,j-1)]-s[id(i-1,j-1)];
//第二遍前缀和是这个点以及之前所有的点被监视的单位的数量,也是上一步置1的原因;
}
}
read(q);
while(q--){
int x1,y1,x2,y2;
read(x1),read(y1),read(x2),read(y2);
if(sum(x1,y1,x2,y2)==(y2-y1+1)*(x2-x1+1)) puts("YES");
else puts("NO");
}
}
}