HDOJ 5480 Conturbatio

来源:互联网 发布:安卓聊天软件源码 编辑:程序博客网 时间:2024/05/16 14:33

题目连接: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(nmQ),肯定是会超时的,得预处理棋盘。
方法一:预处理棋盘里的所有矩形,而且尽量让每个矩形的面积最大
首先按行处理,若i到j行都有车,那就说明这有一个矩形是:i, 1, j - 1, m。同理处理列,有矩形1, i, n, j - 1。

#include <iostream>#include <cstdio>#include <cstring>#include <vector>#define pb push_backusing 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;}
0 0