首页 > 其他分享 >F1. Smooth Sailing (Easy Version)

F1. Smooth Sailing (Easy Version)

时间:2024-01-23 19:01:21浏览次数:36  
标签:F1 格子 ... int island cells Smooth cell Version

F1. Smooth Sailing (Easy Version)

The only difference between the two versions of this problem is the constraint on $q$. You can make hacks only if both versions of the problem are solved.

Thomas is sailing around an island surrounded by the ocean. The ocean and island can be represented by a grid with $n$ rows and $m$ columns. The rows are numbered from $1$ to $n$ from top to bottom, and the columns are numbered from $1$ to $m$ from left to right. The position of a cell at row $r$ and column $c$ can be represented as $(r, c)$. Below is an example of a valid grid.


Example of a valid grid

There are three types of cells: island, ocean and underwater volcano. Cells representing the island are marked with a '#', cells representing the ocean are marked with a '.', and cells representing an underwater volcano are marked with a 'v'. It is guaranteed that there is at least one island cell and at least one underwater volcano cell. It is also guaranteed that the set of all island cells forms a single connected component$^{\dagger}$ and the set of all ocean cells and underwater volcano cells forms a single connected component. Additionally, it is guaranteed that there are no island cells at the edge of the grid (that is, at row $1$, at row $n$, at column $1$, and at column $m$).

Define a round trip starting from cell $(x, y)$ as a path Thomas takes which satisfies the following conditions:

  • The path starts and ends at $(x, y)$.
  • If Thomas is at cell $(i, j)$, he can go to cells $(i+1, j)$, $(i-1, j)$, $(i, j-1)$, and $(i, j+1)$ as long as the destination cell is an ocean cell or an underwater volcano cell and is still inside the grid. Note that it is allowed for Thomas to visit the same cell multiple times in the same round trip.
  • The path must go around the island and fully encircle it. Some path $p$ fully encircles the island if it is impossible to go from an island cell to a cell on the grid border by only traveling to adjacent on a side or diagonal cells without visiting a cell on path $p$. In the image below, the path starting from $(2, 2)$, going to $(1, 3)$, and going back to $(2, 2)$ the other way does not fully encircle the island and is not considered a round trip.

Example of a path that does not fully encircle the island

The safety of a round trip is the minimum Manhattan distance$^{\ddagger}$ from a cell on the round trip to an underwater volcano (note that the presence of island cells does not impact this distance).

You have $q$ queries. A query can be represented as $(x, y)$ and for every query, you want to find the maximum safety of a round trip starting from $(x, y)$. It is guaranteed that $(x, y)$ is an ocean cell or an underwater volcano cell.

$^{\dagger}$A set of cells forms a single connected component if from any cell of this set it is possible to reach any other cell of this set by moving only through the cells of this set, each time going to a cell with a common side.

$^{\ddagger}$Manhattan distance between cells $(r_1, c_1)$ and $(r_2, c_2)$ is equal to $|r_1 - r_2| + |c_1 - c_2|$.

Input

The first line contains three integers $n$, $m$, and $q$ ($3 \leq n, m \leq 10^5$, $9 \leq n \cdot m \leq 3 \cdot 10^5$, $1 \leq q \leq 5$) — the number of rows and columns of the grid and the number of queries.

Each of the following $n$ lines contains $m$ characters describing the cells of the grid. The character '#' denotes an island cell, '.' denotes an ocean cell, and 'v' denotes an underwater volcano cell.

It is guaranteed that there is at least one island cell and at least one underwater volcano cell. It is guaranteed that the set of all island cells forms a single connected component and the set of all ocean cells and underwater volcano cells forms a single connected component. Also, it is guaranteed that there are no island cells at the edge of the grid (that is, at the row $1$, at the row $n$, at the column $1$, and at the column $m$).

The following $q$ lines describe the queries. Each of these lines contains two integers $x$ and $y$ ($1 \leq x \leq n$, $1 \leq y \leq m$) denoting a round trip starting from $(x, y)$.

It is guaranteed that $(x, y)$ is an ocean cell or an underwater volcano cell.

Output

For each query, output a single integer — the maximum safety of a round trip starting from the specified position.

Examples

input

9 9 3
.........
.........
....###..
...v#....
..###....
...##...v
...##....
.........
v........
1 1
9 1
5 7

output

3
0
3

input

3 3 5
..v
.#.
...
1 2
1 3
2 3
2 1
3 2

output

0
0
0
0
0

input

14 13 5
.............
.............
.............
...vvvvvvv...
...v.....v...
...v.###.v...
...v.#.#.v...
...v..v..v...
...v..v..v...
....v...v....
.....vvv.....
.............
.............
.............
1 1
7 7
5 6
4 10
13 6

output

3
0
1
0
2

input

10 11 4
...........
..#######..
..#..#..#..
..#.....#..
..#..v..#..
..#.###.#..
..#.#.#.#..
..#...#.#..
..#####.#..
...........
7 6
3 7
6 8
1 1

output

1
2
3
4

Note

For the first example, the image below shows an optimal round trip starting from $(1, 1)$. The round trip has a safety of $3$ as the minimum Manhattan distance from a cell on the round trip to an underwater volcano is $3$.


Example of an optimal round trip

For the fourth example, remember that it is allowed for Thomas to visit the same cell multiple times in the same round trip. For example, doing so is necessary for the round trip starting from $(7, 6)$.

 

解题思路

  容易知道答案具有二段性,所以考虑二分答案。对于二分值 $d$,我们只能访问距离所有 v 至少为 $d$ 的格子,这样才能保证最后访问的所有格子距离 v 的最小值至少为 $d$,即答案为 $d$。所以只需找到满足该条件且与询问 $(x,y)$ 连通的格子,并判断能否把所有的 # 包围住。

  为了判断某个格子是否满足距离所有的 v 都至少为 $d$,可以用多源 bfs,即把所有 v 的格子压入队列进行 bfs,最后得到的 $\text{dist}$ 数组就是每个格子距离所有的 v 的最小值。因此合法的格子就要满足 $\text{dist}_{i,j} \geq d$。

  而找到所有与 $(x,y)$ 连通的格子则有很多方法,可以从 $(x,y)$ 开始进行 dfs 或 bfs,往上下左右四个方向的合法的格子扩展。或者用并查集,只需枚举每个格子,把四个方向中合法的格子与该格子合并,最后如果 $(i,j)$ 与 $(x,y)$ 在同一个连通块内则有 find({i,j}) = find({x,y})

  最后是判断 $(x,y)$ 所在的连通块能否将所有的 # 包围。反过来思考,某个 # 能否在不访问 $(x,y)$ 连通块内格子的前提下到达边缘处?如果可以则说明则无法将所有的 # 包围,否则可以。因此做法就是随便找一个 # 的格子压入队列进行 bfs(当然也可以 dfs),每次往 $8$ 个方向扩展(除了上下左右外,还要考虑左上、右上、左下和右下),只要扩展的格子之前没被遍历过以及不在 $(x,y)$ 所在的连通块内,就把它压入队列。其中如果在扩展的过程中发现可以扩展到边缘处,则说明无法将 # 包围。

  之所以要往 $8$ 个方向扩展是为了判断下图中未包围的情况,即可以从 $(2,3)$ 走到边缘处 $(1,2)$。

  AC代码如下,时间复杂度为 $O(q \cdot nm)$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 1e5 + 10, M = 3e5 + 10;

int n, m, k, sx, sy;
string g[N];
vector<int> dist[N];
int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, 1, -1};
int fa[M];
vector<bool> vis[N];

int find(int x) {
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}

bool check(int d) {
    iota(fa, fa + n * m, 0);
    queue<array<int, 2>> q;
    // 找到所有连通块
    for (int i = 0; i < n; i++) {
        vis[i].assign(m, false);
        for (int j = 0; j < m; j++) {
            if (g[i][j] == '#' && q.empty()) {    // 随便找到一个是#的格子
                q.push({i, j});
                vis[i][j] = true;
            }
            if (g[i][j] != '#' && dist[i][j] >= d) {    // 往四个方向合并
                for (int k = 0; k < 4; k++) {
                    int x = i + dx[k], y = j + dy[k];
                    if (x < 0 || x >= n || y < 0 || y >= m) continue;
                    if (g[x][y] == '#') continue;
                    if (dist[x][y] < d) continue;    // 格子到v的距离小于d不合法
                    fa[find(x * m + y)] = find(i * m + j);
                }
            }
        }
    }
    // 判断从#出发能否到达边缘处
    while (!q.empty()) {
        auto p = q.front();
        q.pop();
        for (int i = 0; i < 8; i++) {
            int x = p[0] + dx[i], y = p[1] + dy[i];
            if (x < 0 || x >= n || y < 0 || y >= m) continue;
            if (find(x * m + y) == find(sx * m + sy)) continue;    // 不能访问(x,y)连通块中的格子
            if (!x || x == n - 1 || !y || y == m - 1) return false;    // 可以访问边缘处,无法包围#
            if (vis[x][y]) continue;
            vis[x][y] = true;
            q.push({x, y});
        }
    }
    return true;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m >> k;
    for (int i = 0; i < n; i++) {
        cin >> g[i];
    }
    // 把所有是v的格子压入队列
    queue<array<int, 2>> q;
    for (int i = 0; i < n; i++) {
        dist[i].assign(m, 0x3f3f3f3f);
        for (int j = 0; j < m; j++) {
            if (g[i][j] == 'v') {
                q.push({i, j});
                dist[i][j] = 0;
            }
        }
    }
    // 求每个格子到v的最短距离
    while (!q.empty()) {
        auto p = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int x = p[0] + dx[i], y = p[1] + dy[i];
            if (x < 0 || x >= n || y < 0 || y >= m) continue;
            if (dist[x][y] > dist[p[0]][p[1]] + 1) {
                dist[x][y] = dist[p[0]][p[1]] + 1;
                q.push({x, y});
            }
        }
    }
    // 二分答案
    while (k--) {
        cin >> sx >> sy;
        sx--, sy--;
        int l = 0, r = n + m;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (check(mid)) l = mid;
            else r = mid - 1;
        }
        cout << l << '\n';
    }
    
    return 0;
}

 

参考资料

  Editorial for Codeforces Round #919 (Div. 2):https://codeforces.com/blog/entry/122560

标签:F1,格子,...,int,island,cells,Smooth,cell,Version
From: https://www.cnblogs.com/onlyblues/p/17983158

相关文章

  • Inplementation of Binary Search Tree using recursion-local version 3【1月23日学
    点击查看代码#include<iostream>usingnamespacestd;structNode{intdata;Node*left,*right;//注意声明格式};Node*newNode(intx){Node*temp=newNode;temp->data=x;temp->left=temp->right=NULL;returntemp;}......
  • Inplementation of Binary Search Tree using iteration-local version 2【1月23日学
    点击查看代码#include<iostream>usingnamespacestd;structNode{intdata;Node*left;Node*right;};Node*newNode(intx){Node*temp=newNode;temp->data=x;temp->left=temp->right=nullptr;returntemp......
  • libm.so.6: version `GLIBC_2.29' not found
    基础GLIBC是Linux系统中最底层的API,最主要的功能是对系统调用进行了封装,几乎其他任何的运行库都要依赖glibc。因此,切勿擅自通过编译的方式升级,容易将系统搞坏。升级glibc主要是对/lib库中的libc.so.6,libm.so.6,libpthread.so.0和librt.so.1这四个文件的修改[root@taishan-atlas......
  • STM32F105双路隔离型CAN总线转4G控制板 - 二次开发环境搭建和程序下载测试
    <p><iframename="ifd"src="https://mnifdv.cn/resource/cnblogs/product/STM32F105_2CAN/index.html"frameborder="0"scrolling="auto"width="100%"height="1500"></iframe></p>......
  • CF1424M Ancient Language 题解
    1.题意描述一本字典中有\(r\)\((1\leqr\leq10^6)\)个单词,单词长度不超过$10^3$,所有字母都是小写英文字母,但字母排序不是按英文字母排序,求所有出现字母的一种排序,如果不存在,输出"IMPOSSIBLE"。2.题目分析由排序规则可知,对于字符串\(s\)和\(t\),\(s\)排在\(t\)......
  • CF1036F Relatively Prime Powers 题解
    题目分析对于一个不合法的数\(x(x\ge2)\),设\(x=\prodp_i^{r_i}\),令\(g=\gcd(r_1,r_2,\ldots,r_k)\),则\(x=\left(\prodp_i^{r_i/g}\right)^g\),所以\(x\)是一个正整数的\(g\)次方。所以可以枚举上文的\(g\),把每一类不合法方案排除掉,就是答案。设\(f(i)\)表示\(2\)......
  • CF1914D Three Activities
    题目大意给定三个数组\(a,b,c\)找三个互不相同的整数\(i,j,k\)使得\(a_i+b_j+c_k\)的值最大.思路首先想到的当然是枚举\(i,j,k\)然后找到最大值,但这种方法的时间复杂度是\(O(n^3)\),显然会喜提\(TLE\).当然由瞪眼法可知,因为我们只需要找到\(a_i+b_j......
  • 从CF1875C学习lowbit运算判断是否为 2 的 k 次幂
    Problem-1875C-Codeforces本题判断无解的时候要判断该数是否为2的k次幂,我的做法是预处理出2的次幂数表。看题解发现可以用lowbit操作。lowbit操作intlowbit(intx){returnx&(-x);}根据补码原理,该操作可以求出来X最靠右的\(1\)构成的数。判断\(x\)......
  • 从CF1878E学习前缀和维护二进制拆位分析思想
    Problem-1878E-Codeforces这题我想到了个大概,按位与的话结果肯定是递减的,而且要从二进制每一位下手,但是思路只停留在暴力对整个数操作。当然,利用这个性质,肯定要二分。拆位思想比如要计算111000111011100100010我们知道最后结果肯定是留下都有\(1\)的位0100000......
  • CF1922F Replace on Segment
    看到有区间操作,结合\(n\le100\)的数据范围,直接考虑区间dp。设\(f_{l,r,x}\)表示将区间\([l,r]\)全部替换成\(x\)的最小步数。首先有\(f_{l,r,x}=\max_{p=l}^{r-1}f_{l,p,x}+f_{p+1,r,x}\),但这无法将该状态下的所有的情况都转移到,所以考虑再设一个\(g_{l,r,x}\)表示......