CodeforcesRound#749(Div.1+Div.2,basedonTechnocup2022EliminationRound1)-C. Omkar and Determination-题解

在这里插入代码片

Codeforces Round #749 (Div. 1 + Div. 2, based on Technocup 2022 Elimination Round 1) - C. Omkar and Determination

传送门
Time Limit: 2 seconds
Memory Limit: 256 megabytes

Problem Description

The problem statement looms below, filling you with determination.

Consider a grid in which some cells are empty and some cells are filled. Call a cell in this grid exitable if, starting at that cell, you can exit the grid by moving up and left through only empty cells. This includes the cell itself, so all filled in cells are not exitable. Note that you can exit the grid from any leftmost empty cell (cell in the first column) by going left, and from any topmost empty cell (cell in the first row) by going up.

Let’s call a grid determinable if, given only which cells are exitable, we can exactly determine which cells are filled in and which aren’t.

You are given a grid a of dimensions n × m n×m n×m , i. e. a grid with n n n rows and m m m columns. You need to answer q q q queries ( 1 ≤ q ≤ 2 ⋅ 1 0 5 ) (1≤q≤2⋅10^5) (1q2105). Each query gives two integers x 1 , x 2 ( 1 ≤ x 1 ≤ x 2 ≤ m ) x_1,x_2 (1≤x_1≤x_2≤m) x1,x2(1x1x2m) and asks whether the subgrid of a consisting of the columns x 1 , x 1 + 1 , … , x 2 − 1 , x 2 x_1,x_1+1,…,x_2−1,x_2 x1,x1+1,,x21,x2 is determinable.

Input

The first line contains two integers n , m ( 1 ≤ n , m ≤ 1 0 6 , n m ≤ 1 0 6 ) n,m (1≤n,m≤10^6, nm≤10^6) n,m(1n,m106,nm106) — the dimensions of the grid a.

n n n lines follow. The y y y-th line contains m characters, the x x x-th of which is ‘X’ if the cell on the intersection of the the y y y-th row and x x x-th column is filled and “.” if it is empty.

The next line contains a single integer q ( 1 ≤ q ≤ 2 ⋅ 1 0 5 ) q (1≤q≤2⋅10^5) q(1q2105) — the number of queries.

q q q lines follow. Each line contains two integers x 1 x_1 x1 and x 2 ( 1 ≤ x 1 ≤ x 2 ≤ m ) x_2 (1≤x_1≤x_2≤m) x2(1x1x2m), representing a query asking whether the subgrid of a containing the columns x 1 , x 1 + 1 , … , x 2 − 1 , x 2 x_1,x_1+1,…,x_2−1,x_2 x1,x1+1,,x21,x2 is determinable.

Output

For each query, output one line containing “YES” if the subgrid specified by the query is determinable and “NO” otherwise. The output is case insensitive (so “yEs” and “No” will also be accepted).

Sample Input

4 5
..XXX
...X.
...X.
...X.
5
1 3
3 3
4 5
5 5
1 5

Sample Onput

YES
YES
NO
YES
NO

Note

For each query of the example, the corresponding subgrid is displayed twice below: first in its input format, then with each cell marked as “E” if it is exitable and “N” otherwise.

For the first query:

..X EEN
... EEE
... EEE
... EEE

For the second query:

X N
. E
. E
. E

Note that you can exit the grid by going left from any leftmost cell (or up from any topmost cell); you do not need to reach the top left corner cell to exit the grid.

For the third query:

XX NN
X. NN
X. NN
X. NN

This subgrid cannot be determined only from whether each cell is exitable, because the below grid produces the above “exitability grid” as well:

XX
XX
XX
XX

For the fourth query:

X N
. E
. E
. E

For the fifth query:

..XXX EENNN
...X. EEENN
...X. EEENN
...X. EEENN

This query is simply the entire grid. It cannot be determined only from whether each cell is exitable because the below grid produces the above “exitability grid” as well:

..XXX
...XX
...XX
...XX

题目大意

  • 给你一个地图,X是障碍.是空地

  • 每次可以向左或向上移动,但不能经过任何一处障碍

  • 你可以从地图最左边或最上边离开地图

  • 现在有Q次询问,每次询问都将地图的第 l l l 列到第 r r r 列作为新的地图

  • 在新的地图中,你可以确定出所有的 可逃离点不可逃离点,并把这些点绘制成一张新的地图给别人看

  • 问别人看到你这张可否逃离点地图后,能否唯一还原出之前的障碍空地地图

解题思路

这题描述有点绕

假如给你了一个可否逃离点地图,你看到后是否可以唯一还原出障碍空地地图呢?

如果可以唯一还原,那么每个点的信息都必须是有效的。也就是说不能通过其他点推断出这个点是否可以逃离。如果通过其他点已经确定这点必定不可逃离了,那么无论这一点的原障碍空地地图中是空地还是障碍,这点都是无法逃离点,此时不能还原。

那么什么时候根据其他的点就能判断这一点必定不可逃离呢?

如果这一点的上面的点和这一点的左边的点都不可逃离,那么这一点必定不可逃离,无论它是空地还是障碍。

因为这点只能向上或向左走。

此时,可否逃离点地图的这点必是不可逃离点,因而无法还原出这点的原地图是空地还是障碍。

因此我们可以寻找这样的图形:

在这里插入图片描述

2 × 2 2\times2 2×2的格子里,如果右上角和左下角都是障碍,那么同时包含这两列的可否逃离点地图就不可还原。

我们可以用 O ( n m ) O(nm) O(nm)的时间复杂度的时间求出所有的这样的列,存到Swords数组中。之后给出的所有询问,只要同时包含这两列,都是No。否则就是Yes。

还有一个问题就是询问次数数量级是 2 ∗ 1 0 5 2*10^5 2105,而不可同时包含数组Swords的数量级也可能是 1 0 6 ( → m ) 10^6 (\to m) 106m级别,暴力求解每个询问还是要超时,因此我们还要处理一下所有的询问,把所有的询问进行离线操作。

读入了所有的询问 l l l r r r后,我们把询问排个序,依据是 l l l从小到大优先, r r r从小到大其次。

蓝色的横线代表排序后的询问:
在这里插入图片描述

假如我们在Swords中记录下了 3 3 3个值: 1 , 3 , 5 1,3,5 1,3,5(也就是说同时包含 1 ∼ 2 1\sim2 12 3 ∼ 4 3\sim4 34 5 ∼ 6 5\sim6 56的地图都输出No)

我们可以用一个变量to来记录处理到了哪个询问,假如这次处理的是 1 ∼ 2 1\sim2 12,那么我们这次就处理所有未处理过的且l<2的询问。包含 1 ∼ 2 1\sim2 12就No,不包含就Yes。

这样下来,每个询问都只处理了一次,处理的总时间复杂度是 O ( Q ) O(Q) O(Q)(小于排序复杂度 O ( Q log ⁡ Q ) O(Q\log Q) O(QlogQ)


AC代码

/*
 * @Author: LetMeFly
 * @Date: 2021-10-17 19:53:37
 * @LastEditors: LetMeFly
 * @LastEditTime: 2021-10-18 23:29:26
 */ // LastEditTime: 2021-10-17 20:06:52
#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
char c[1000010]; // 用来输入一行
struct querys { // 询问
    int l, r, th; // l到r,第th次询问
    bool no; // 是否应输出No
}q[200010];
bool cmp(const querys &a, const querys &b) { // 排序规则1:l从小到大优先,r从小到大其次
    if (a.l != b.l) return a.l < b.l;
    if (a.r != b.r) return a.r < b.r;
    return a.th < b.th;
}
bool cmp2(const querys &a, const querys &b) { // 排序规则2:按询问顺序从小到大排序(为了输出)
    return a.th < b.th;
}
int main() {
    int n,m;
    cin>>n>>m;
    vector<bool> a[n]; // 存储原始地图
    for (int i = 0; i < n; i++) {
        a[i].resize(m); // 每一行都有m列
    }
    for (int i = 0; i < n; i++) {
        scanf("%s", c); // 读入这一行
        for (int j = 0; j < m; j++) {
            a[i][j] = c[j] == 'X'; // 处理这一行的每一列
        }
    }
    vector<int>Swords; // 假如a在Swords中,那么同时包含第a列和第a+1列的子地图都应输出No。因每次Swords[i]都把询问一分两半,故美其名曰“宝剑”
    for (int j = 0; j + 1 < m; j++) {
        for (int i = 1; i < n; i++) {
            if (a[i][j] && a[i - 1][j + 1]) { // 2x2的方格,左下角和右上角都是X
                Swords.push_back(j); // 就存下这一列
                break; // 退出循环
            }
        }
    }
    int Q;
    cin>>Q; // Q次询问
    for (int i = 0; i < Q; i++) {
        scanf("%d%d", &q[i].l, &q[i].r);
        q[i].l--, q[i].r--;
        q[i].th = i;
        q[i].no = false;
    }
    sort(q, q + Q, cmp); // 依据规则1进行排序
    int to = 0; // 该处理哪个询问
    for (int &left: Swords) { // 遍历Swords中的每个元素
        int right = left + 1;
        int newTo = to; // 这次处理之后该处理哪个询问
        while (newTo < Q && q[newTo].l < right) {
            newTo++;
        }
        // [to, newTo)是未处理的query
        for (int i = to; i < newTo; i++) {
            if (q[i].l <= left && q[i].r >= right) { // 如果询问把这两列包含在其中
                q[i].no = true; // 就应该输出No
            }
        }
    }
    sort(q, q + Q, cmp2); // 恢复成发出询问的顺序(其实这里可以换成桶排)
    for (int i = 0; i < Q; i++) { // 输出
        if (q[i].no) puts("NO");
        else puts("YES");
    }
    return 0;
}

原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/120836197

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tisfy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值