HDU - 6514 Monitor ( 二位前缀和+差分 )
题意:
给你n和m,表示有一个n*m的矩阵(n>=1, m>=1, n*m<=1e7),初始全0,接下来一个数p(p<=1e6),接下来p个矩阵的左上角和右下角的坐标。
把这位于这些矩阵内的格子置为1,再接下来一个数q(1<=1e6),接下来q个矩阵的左上角和右下角的坐标,对于每个矩阵,如果它包含的每个格子都是1,则输出YES,否则输出NO。
思路:
因为n和m都可能是1e7的,所以没法开二维的数组,直接开一个1e7的一维数组当做二维数组用。在维护二维前缀和前需要用差分思想,把1e6组插入给记录下来,然后处理差分数组,变成计数数组,再进行二维前缀和。
二维差分时注意需要在哪些点加减,这里画图理解一下。
下图表示,在这个矩形范围内全部加1, 那么只需要在图示四个点标记差分数组就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e7+10;
int a[maxn];
int n,m;
int getid( int i, int j )
{
return i*(m+2)+j; // 在一行里可能用到0,和n+1, 所以需要乘(m+2)
}
int main()
{
int x1,x2,y1,y2,l,q;
while ( cin>>n>>m ) {
cin >> l;
memset(a,0,sizeof(a));
while ( l-- ) {
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
a[ getid(x1,y1) ] ++;
a[ getid(x1,y2+1) ] --;
a[ getid(x2+1,y1) ] --;
a[ getid(x2+1,y2+1) ] ++;
}
for ( int i=1; i<=n; i++ ) { //把差分数组转化成计数数组
for ( int j=1; j<=m; j++ ) {
a[ getid(i,j) ] += a[ getid(i-1,j) ] + a[ getid(i,j-1) ] - a[ getid(i-1,j-1) ];
}
}
for ( int i=1; i<=n; i++ ) { //大于1的当成1
for ( int j=1; j<=m; j++ ) {
if ( a[ getid(i,j) ]>0 ) a[ getid(i,j) ] = 1;
}
}
for ( int i=1; i<=n; i++ ) { //把计数数组转换成二维前缀和
for ( int j=1; j<=m; j++ ) {
a[ getid(i,j) ] += a[ getid(i-1,j) ] + a[ getid(i,j-1) ] - a[ getid(i-1,j-1) ];
}
}
cin >> q;
while ( q-- ) {
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
int tot = a[ getid(x2,y2) ] - a[ getid(x2,y1-1) ] - a[ getid(x1-1,y2) ] + a[ getid(x1-1,y1-1) ];
if ( tot==(x2-x1+1)*(y2-y1+1) ) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}