题目连接:HDOJ5480
题目大意:有t组测试数据,每组给一个n * m的矩形棋盘格子,棋盘内有很多车(x, y),每个车的攻击范围是这个车所在的行x和列y,共有K辆车,然后有Q次询问,每次询问给一个矩形(四个数描述矩形,左下角和右上角),问给的矩形的每个格子都能否被车攻击,是就输出“Yes”,否则“No”。
数据范围:
1 ≤ n , m, K, Q ≤ 100,000.
1 ≤ x ≤ n, 1 ≤ y ≤m.
1 ≤ x1 ≤ x2 ≤ n, 1 ≤ y1 ≤ y2 ≤m.
注意:
给的矩形的左下角和右上角的意思,这个坐标系不是数学上的坐标系,而是计算机上的坐标系。
数据范围很大,若每次询问在去扫描棋盘,时间复杂度是
O(n∗m∗Q)
,肯定是会超时的,得预处理棋盘。
方法一:预处理棋盘里的所有矩形,而且尽量让每个矩形的面积最大。
首先按行处理,若i到j行都有车,那就说明这有一个矩形是:i, 1, j - 1, m。同理处理列,有矩形1, i, n, j - 1。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#define pb push_back
using namespace std;
const int MAXN = 1e5+5;
struct rectangle
{
int x1, y1, x2, y2;
rectangle(int _x1, int _y1, int _x2, int _y2)
{
x1 = _x1;
y1 = _y1;
x2 = _x2;
y2 = _y2;
}
};
bool row[MAXN], col[MAXN];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
memset(row, false, sizeof row);
memset(col, false, sizeof col);
int n, m, k, q;
scanf("%d%d%d%d", &n, &m, &k, &q);
for(int i = 0; i < k; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
row[x] = true;
col[y] = true;
}
vector <rectangle> vec;
for(int i = 1; i <= n; ++i)//处理i行为起点的最大矩形
{
int j = i;
while(row[j] && j <= n) j++;
if(j != i)
{
vec.pb(rectangle(i, 1, j - 1, m));
i = j - 1;
}
}
for(int i = 1; i <= m; ++i)//处理i列为起点的最大矩形
{
int j = i;
while(col[j] && j <= m) j++;
if(j != i)
{
vec.pb(rectangle(1, i, n, j - 1));
i = j - 1;
}
}
for(int i = 0; i < q; ++i)
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
bool f = false;
for(int j = 0; j < vec.size() && !f; ++j)//在处理的矩形里,查看有没有矩形能够包括给的矩形
{
if(vec[j].x1 <= x1 && vec[j].y1 <= y1 && vec[j].x2 >= x2 && vec[j].y2 >= y2)
f = true;
}
puts(f? "Yes": "No");
}
}
return 0;
}
方法二:预处理棋盘的所有矩形,但是不记录矩形的坐标。
按行处理,row[i]表示以i行为结束行的最大矩形的行数。同理列,col[i]表示以i列为结束列的最大矩形的列数。
转移方程:row[i] += row[i - 1];
col[i] += col[i - 1];
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1e5+5;
int row[MAXN], col[MAXN];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
memset(row, 0, sizeof row);
memset(col, 0, sizeof col);
int n, m, k, q;
scanf("%d%d%d%d", &n, &m, &k, &q);
for(int i = 0; i < k; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
row[x] = col[y] = 1;
}
for(int i = 1; i <= n; ++i)//行
if(row[i]) row[i] += row[i - 1];
for(int i = 1; i <= m; ++i)//列
if(col[i]) col[i] += col[i - 1];
for(int i = 0; i < q; ++i)
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
if(row[x2] >= x2 - x1 + 1 || col[y2] >= y2 - y1 + 1) puts("Yes");
else puts("No");
}
}
return 0;
}