HDOJ 5480 Conturbatio

题目连接: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_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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值