hdu 6514 Monitor(二维差分区间+哈希)

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 163840/163840 K (Java/Others)
Total Submission(s): 514    Accepted Submission(s): 160


 

Problem Description

Xiaoteng has a large area of land for growing crops, and the land can be seen as a rectangle of n×m.

But recently Xiaoteng found that his crops were often stolen by a group of people, so he decided to install some monitors to find all the people and then negotiate with them.

However, Xiao Teng bought bad monitors, each monitor can only monitor the crops inside a rectangle. There are p monitors installed by Xiaoteng, and the rectangle monitored by each monitor is known.

Xiao Teng guess that the thieves would also steal q times of crops. he also guessed the range they were going to steal, which was also a rectangle. Xiao Teng wants to know if his monitors can see all the thieves at a time.

 

 

Input

There are mutiple test cases.

Each case starts with a line containing two integers n,m(1≤n,1≤m,n×m≤107) which represent the area of the land.

And the secend line contain a integer p(1≤p≤106) which represent the number of the monitor Xiaoteng has installed. This is followed by p lines each describing a rectangle. Each of these lines contains four intergers x1,y1,xand y2(1≤x1≤x2≤n,1≤y1≤y2≤m) ,meaning the lower left corner and upper right corner of the rectangle.

Next line contain a integer q(1≤q≤106) which represent the number of times that thieves will steal the crops.This is followed by q lines each describing a rectangle. Each of these lines contains four intergers x1,y1,xand y2(1≤x1≤x2≤n,1≤y1≤y2≤m),meaning the lower left corner and upper right corner of the rectangle.

 

 

Output

For each case you should print q lines.

Each line containing YES or NO mean the all thieves whether can be seen.

 

 

Sample Input

 

6 6

3

2 2 4 4

3 3 5 6

5 1 6 2

2

3 2 5 4

1 5 6 5

 

 

Sample Output

 

YES

NO

(关于前缀和的博客:https://blog.csdn.net/K_R_forever/article/details/81775899

(思路:新的知识,以前做过一维差分,这次长见识了,二维差分。。。至于原理是啥,我也不是很清楚,记住就好了吧。

对于一维,l~r区间上的值变化v的话,只需把c[l]+v,c[r+1]-v,这里的c[i]表示下标为i~n的数变了多少,然后求前缀和即可。对于二维的,若给出的变化区间的左下角坐标(x1,y1),右上角坐标为(x2,y2)。则只需要c[x1][y1]+v,c[x2+1][y2+1]+v,c[x2+1][y1]-v,

c[x1][y2+1]-v,然后求二维前缀和即可。对于此题我们差分完后,先求一次前缀和,得到的是这个点被覆盖了多少次,如果大于0,则这个点被覆盖了值置为1,否则置为0,再求一遍前缀和便可以得到在(1,1)到(i,j)这个矩形内被覆盖的点的个数。最后根据前缀和判断即可。此题需要数组太大,还需哈希一下,并且注意按(i,j)哈希为(i-1)*m+j的话,(i,m),(i+1,0)的哈希值是一样的,因为(i+1,0)的值没用,所以遇到时不用更新。)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#define ll long long
using namespace std;
const int N=2e7+10;
int c[N];
int n,m;
int getpos(int i,int j)
{
	if(i==0||j==0||i>n||j>m) return 0;
	else return (i-1)*m+j;
}
void add(int x,int y,int v)
{
	if(getpos(x,y)==0) return ;
	else 	c[getpos(x,y)]+=v;	
} 
int val(int i,int j)
{
	return c[getpos(i,j)];
}

int main(void)
{

	while(~scanf("%d%d",&n,&m))
	{
		for(int i=1;i<=n*m;i++)
		{
			c[i]=0;
		} 	
		int p,q,x1,x2,y1,y2;
		scanf("%d",&p);
		for(int i=0;i<p;i++)
		{
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			add(x2+1,y2+1,1);
			add(x1,y1,1);
			add(x2+1,y1,-1);
			add(x1,y2+1,-1);
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				c[(i-1)*m+j]+=val(i,j-1)+val(i-1,j)-val(i-1,j-1);
				//cout<<i<<" "<<j<<" "<<c[(i-1)*m+j]<<endl;
			}
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				c[(i-1)*m+j]=c[(i-1)*m+j]>0;
				//cout<<i<<" "<<j<<" "<<c[(i-1)*m+j]<<endl;
			}
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				c[(i-1)*m+j]=val(i,j-1)+val(i-1,j)-val(i-1,j-1)+c[(i-1)*m+j];
				//cout<<i<<" "<<j<<" "<<c[(i-1)*m+j]<<endl;		
			}
		}
		int x;			
		scanf("%d",&q);
		while(q--)
		{
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			x=val(x1-1,y1-1)+val(x2,y2)-val(x2,y1-1)-val(x1-1,y2);
			//cout<<x<<" "<<(x2-x1+1)*(y2-y1+1)<<endl;
			if(x==(x2-x1+1)*(y2-y1+1))
				printf("YES\n");
			else
				printf("NO\n");
		}	
	}
	
	return 0;	
} 
/*
6 6
3
2 2 4 4
3 3 5 6
5 1 6 2
2
3 2 5 4
1 5 6 5
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值