Description
给定一张网格图。图中的两个黑点右边当且仅当相邻。
求子网格图
(x1,y1,x2,y2)
中联通块的个数。
保证两个点之间不连通或只存在一条简单路径。
Solution
森林的联通块个数=点数-边数。
#include <bits/stdc++.h>
using namespace std;
const int N = 2020;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
inline void read(int &x) {
static char c; x = 0;
for (c = get(); c < '0' || c > '9'; c = get());
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
inline void read(char *ch) {
static char c; int len = 0;
for (c = get(); c < '0' || c > '1'; c = get());
for (; c == '0' || c == '1'; c = get()) ch[len++] = c;
}
int n, m, q, x1, x2, y11, y2, E, V;
char ch[N][N];
int num[N][N], edg[N][N];
int pr1[N][N], pr2[N][N];
inline int Edge(int x, int y) {
return (ch[x][y] == '1' && ch[x][y - 1] == '1') + (ch[x][y] == '1' && ch[x - 1][y] == '1');
}
int main(void) {
read(n); read(m); read(q);
for (int i = 1; i <= n; i++) read(ch[i] + 1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
num[i][j] = num[i - 1][j] + num[i][j - 1] - num[i - 1][j - 1] + (ch[i][j] == '1');
for (int i = 2; i <= n; i++)
for (int j = 1; j <= m; j++)
pr1[i][j] = pr1[i][j - 1] + (ch[i][j] == '1' && ch[i - 1][j] == '1');
for (int i = 1; i <= n; i++)
for (int j = 2; j <= m; j++)
pr2[i][j] = pr2[i - 1][j] + (ch[i][j] == '1' && ch[i][j - 1] == '1');
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
edg[i][j] = edg[i - 1][j] + edg[i][j - 1] - edg[i - 1][j - 1] + Edge(i, j);
while (q--) {
read(x1); read(y11); read(x2); read(y2);
E = edg[x2][y2] - edg[x2][y11 - 1] - edg[x1 - 1][y2] + edg[x1 - 1][y11 - 1];
E -= pr1[x1][y2] - pr1[x1][y11 - 1] + pr2[x2][y11] - pr2[x1 - 1][y11];
V = num[x2][y2] - num[x2][y11 - 1] - num[x1 - 1][y2] + num[x1 - 1][y11 - 1];
printf("%d\n", V - E);
}
return 0;
}