Description
给定一个 (n imes m) 的 01矩阵。当矩阵做一次迭代,所有单元格就行如下变换:
- 如果一个单元格周围没有有一个与该格状态相同的单元格,那么这个单元格的状态不会改变。
- 否则,(1 ightarrow 0, 0 ightarrow 1)。
如果两个单元格有邻边则相邻。
现在一个叫 Orac 的睿智要问你 (t) 个问题:每次询问给定一个三元组 ((i, j, q)),表示在第 (i) 行第 (j) 列的位置,整个矩阵经过 (q) 次迭代后,的状态(0/1)。
Hint
- (1le n,mle 10^3)
- (1le tle 10^5)
- (1le qle 10^{18})
Solution
首先建图,将一个状态相同的连通块缩成一个点,记录一下这个点的大小 ( ext{size})。相邻的联通快就连边。
然后可以发现,一次迭代之后,连通块会向外拓展一层。对于一个 ( ext{size} = 1) (在原图上表现为孤立的单元格)的结点来说,如果连通块尚未拓展到此处,那么它的状态将一直不变。
于是,我们需要在新图上求出 每一个 ( ext{size} = 1) 的结点距与之最近的连通块的距离 ( ext{dis})。
要求出 ( ext{dis}),显然不可行的方法是枚举每一个 ( ext{size} = 1) 的点然后分别搜索或求 SSSP。
但是我们可以倒着来——选出所有 ( ext{size}>1) 的结点来求,其实最终效果是一样的。
但还是不能直接爆搜,这样会 Time limit exceeded on pretest 10
。本蒟蒻用的方法是将所有这些点塞入队列,然后跑 spfa
。
于是通过此题。
Code
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : Codeforces 1349C Orac and Game of Life
*/
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e3 + 5;
const int V = N * N;
int n, m, t;
char str[N][N];
int bl[N][N];
int node = 0;
vector<int> G[V];
bool statu[V];
int size[V], dis[V];
const int dx[] = {0, 0, -1, 1};
const int dy[] = {-1, 1, 0, 0};
void fill(int x, int y, int c) {
bl[x][y] = c, ++size[c];
char tmp = str[x][y];
for (register int i = 0; i < 4; i++) {
x += dx[i], y += dy[i];
if (x >= 1 && x <= n && y >= 1 && y <= m)
if (str[x][y] == tmp && !bl[x][y]) fill(x, y, c);
x -= dx[i], y -= dy[i];
}
}
bool inq[V];
void initdis() { // 陈年spfa板子
queue<int> Q;
for (register int i = 1; i <= node; i++)
if (size[i] > 1) Q.push(i), inq[i] = 1;
while(!Q.empty())
{
int cur=Q.front(); Q.pop();
inq[cur]=false;
for(register int i=0;i<G[cur].size();i++)
{
int nxt=G[cur][i],wei=dis[cur]+1;
if(wei<dis[nxt])
{
dis[nxt]=wei;
if(inq[nxt]) continue;
Q.push(nxt),inq[nxt]=true;
}
}
}
}
signed main() {
scanf("%d%d%d", &n, &m, &t);
for (register int i = 1; i <= n; i++)
scanf("%s", str[i] + 1);
for (register int i = 1; i <= n; i++)
for (register int j = 1; j <= m; j++)
if (bl[i][j] == 0) fill(i, j, ++node);
for (register int i = 1; i <= n; i++)
for (register int j = 1; j <= m; j++)
for (register int k = 0; k < 4; k++)
if (1 <= i + dx[k] && i + dx[k] <= n)
if (1 <= j + dy[k] && j + dy[k] <= m)
if (bl[i][j] != bl[i + dx[k]][j + dy[k]]) {
G[bl[i + dx[k]][j + dy[k]]].push_back(bl[i][j]);
G[bl[i][j]].push_back(bl[i + dx[k]][j + dy[k]]);
}
for (register int i = 1; i <= node; i++) {
sort(G[i].begin(), G[i].end());
G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end());
}
memset(dis, 0x3f, sizeof dis);
for (register int i = 1; i <= node; i++)
if (size[i] > 1) dis[i] = 0;
initdis();
while (t--) {
int x, y; long long q;
scanf("%d%d%lld", &x, &y, &q);
if (dis[bl[x][y]] == 0x3f3f3f3f) {
printf("%d
", str[x][y] - '0');
continue;
}
int ans = str[x][y] - '0';
ans ^= (max(0ll, q - dis[bl[x][y]]) & 1);
printf("%d
", ans);
}
return 0;
}