给你一个矩阵,然后每次问你一个矩阵有多少个连通块。
矩阵每个位置有颜色,如果两个相邻的位置颜色相同那它们就是连通的。
Paint by Letters P
题目大意
给你一个矩阵,然后每次问你一个矩阵有多少个连通块。
矩阵每个位置有颜色,如果两个相邻的位置颜色相同那它们就是连通的。
思路
由于这个图是平面图,我们考虑一个公式叫做欧拉公式,V−E+F=2。
然后如果有多个连通块的话,就是 V−E+F=C+1。
(V 是点数,E 是边数,V 是区域数,无界域也算,C 就是连通块数)
点数很好求,边数你搞前缀和也可以求,接着问题就是如何求区域数。
我们可以把它转化为求对偶图的点数。
然而直接转对偶图很麻烦,我们考虑把矩阵每个格子四边的点当做对偶图的点,然后就是求对偶图的连通块数。
至于这里的求连通块数我们可以直接 bfs 跑。
然后要怎么求一个区域的连通块数呢?
我们想到给每个对偶图连通块选一个位置标记,然后一开始我们直接看矩阵里面有多少个标记。(二维前缀和)
然后有可能因为它是一个区域,可能有一些你算到的连通块其实是连着无界域的。
那你考虑这些连通块一定是连出去了,你考虑枚举这个矩阵在外面一层的边界,如果这个边界属于的连通块的标记在这个矩阵里面,就要把这个标记去掉。
(记得判重,因为一个矩阵可能会被多次查到)
然后由于你这里没有算无界域,所以你这里的减一就把那里的加一消掉了。
代码
#include<queue>
#include<cstdio>
using namespace std;
int n, m, Q, a[1011][1011], bj[1011][1011];
int x1, x2, y1, y2, V, E, F, ans;
int lnm[2][1011][1011], col[1011][1011];
bool in[1011][1011], use[1000011];
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
queue <pair<int, int> > q;
pair <int, int> bjp[1000011];
char c;
bool bfs_ck(int x1, int y1, int x2, int y2) {
if (x1 == x2) return a[x1][max(y1, y2)] != a[x1 + 1][max(y1, y2)];
return a[max(x1, x2)][y1] != a[max(x1, x2)][y1 + 1];
}
void bfs(int x, int y) {
while (!q.empty()) q.pop();
col[0][0]++;
bj[x][y]++;
bjp[col[0][0]] = make_pair(x, y);
q.push(make_pair(x, y));
col[x][y] = col[0][0];
bool out = 0;
while (!q.empty()) {
int x = q.front().first, y = q.front().second;
q.pop();
for (int i = 0; i < 4; i++) {
if (!bfs_ck(x, y, x + dx[i], y + dy[i])) continue;
if (x + dx[i] < 1 || x + dx[i] > n || y + dy[i] < 1 || y + dy[i] > m) {
out = 1; continue;
}
if (!col[x + dx[i]][y + dy[i]]) {
col[x + dx[i]][y + dy[i]] = col[0][0];
q.push(make_pair(x + dx[i], y + dy[i]));
}
}
}
if (out) {
bj[x][y]--;
bjp[col[0][0]] = make_pair(0, 0);
}
}
int get_nm(int now[1011][1011], int x1, int y1, int x2, int y2) {
return now[x1][y1] - (y2 ? now[x1][y2 - 1] : 0) - (x2 ? now[x2 - 1][y1] : 0) + ((x2 && y2) ? now[x2 - 1][y2 - 1] : 0);
}
bool inside(int x1, int y1, int x2, int y2, pair <int, int> now) {
if (now.first < x1 || now.first > x2) return 0;
if (now.second < y1 || now.second > y2) return 0;
return 1;
}
int main() {
scanf("%d %d %d", &n, &m, &Q);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
c = getchar();
while (c < 'A' || c > 'Z') c = getchar();
a[i][j] = c - 'A' + 1;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
if (a[i][j] == a[i][j - 1]) lnm[0][i][j] = 1;
if (a[i][j] == a[i - 1][j]) lnm[1][i][j] = 1;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
lnm[0][i][j] += lnm[0][i][j - 1] + lnm[0][i - 1][j] - lnm[0][i - 1][j - 1];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
lnm[1][i][j] += lnm[1][i][j - 1] + lnm[1][i - 1][j] - lnm[1][i - 1][j - 1];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (!col[i][j]) {
bfs(i, j);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
bj[i][j] += bj[i][j - 1] + bj[i - 1][j] - bj[i - 1][j - 1];
for (int qq = 1; qq <= Q; qq++) {
ans = 0;
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
V = (x2 - x1 + 1) * (y2 - y1 + 1);
E = get_nm(lnm[0], x2, y2, x1, y1 + 1) + get_nm(lnm[1], x2, y2, x1 + 1, y1);
F = get_nm(bj, x2 - 1, y2 - 1, x1, y1);
for (int i = x1; i <= x2; i++) {
if (!use[col[i][y1 - 1]] && inside(x1, y1, x2 - 1, y2 - 1, bjp[col[i][y1 - 1]]))
use[col[i][y1 - 1]] = 1, F--;
if (!use[col[i][y2]] && inside(x1, y1, x2 - 1, y2 - 1, bjp[col[i][y2]]))
use[col[i][y2]] = 1, F--;
}
for (int i = y1; i <= y2; i++) {
if (!use[col[x1 - 1][i]] && inside(x1, y1, x2 - 1, y2 - 1, bjp[col[x1 - 1][i]]))
use[col[x1 - 1][i]] = 1, F--;
if (!use[col[x2][i]] && inside(x1, y1, x2 - 1, y2 - 1, bjp[col[x2][i]]))
use[col[x2][i]] = 1, F--;
}
for (int i = x1; i <= x2; i++) {
use[col[i][y1 - 1]] = 0;
use[col[i][y2]] = 0;
}
for (int i = y1; i <= y2; i++) {
use[col[x1 - 1][i]] = 0;
use[col[x2][i]] = 0;
}
printf("%d\n", F + V - E);
for (int i = x1; i <= x2; i++)
for (int j = y1; j <= y2; j++)
in[i][j] = 0;
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现