题意:
给定 n*m 的表格,开始全为空,然后每次给定一行或者一列涂黑,然后问当前白色方格的块数
思路:
将每次染黑的操作离线,涂黑的方格每次加一,然后从后往前,将重新变白的格子用并查集维护一下,每次只要维护其上下左右四个方向合并就行
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 7;
const int maxd = 1e4 + 7;
int n, m, q, num;
int f[maxn*maxn], a[maxn][maxn];
int x1[maxd], y1[maxd], x2[maxd], y2[maxd];
int ans[maxd];
int dx[5] = {0, 0, 1, -1};
int dy[5] = {1, -1, 0, 0};
void init(int n) {
for(int i = 1; i <= n; ++i) {
f[i] = i;
}
}
int find_(int x) {
return ( f[x] == x ? x : f[x] = find_(f[x]));
}
void unit(int x, int y) {
x = find_(x), y = find_(y);
if(x == y) return;
num--;
f[x] = y;
}
int id(int x, int y) {
return ((x-1)*m + y);
}
void work(int x, int y) {
for(int k = 0; k < 4; ++k) {
int nx = x + dx[k], ny = y + dy[k];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && !a[nx][ny]) {
unit(id(x,y), id(nx,ny));
}
}
}
int main() {
while(~scanf("%d%d%d", &n, &m, &q)) {
init(n*m);
memset(a, 0, sizeof a);
for(int i = 1; i <= q; ++i) {
scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
if(x1[i] == x2[i]) {
for(int j = y1[i]; j <= y2[i]; ++j) a[x1[i]][j]++;
}
else {
for(int j = x1[i]; j <= x2[i]; ++j) a[j][y1[i]]++;
}
}
num = n * m;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
if(!a[i][j]) {
work(i, j);
}
else {
num--;
}
}
}
for(int i = q; i >= 1; --i) {
ans[i] = num;
if(x1[i] == x2[i]) {
for(int j = y1[i]; j <= y2[i]; ++j) {
a[x1[i]][j]--;
if(a[x1[i]][j]) continue;
num++;
work(x1[i], j);
}
}
else {
for(int j = x1[i]; j <= x2[i]; ++j) {
a[j][y1[i]]--;
if(a[j][y1[i]]) continue;
num++;
work(j, y1[i]);
}
}
}
for(int i = 1; i <= q; ++i) {
printf("%d\n", ans[i]);
}
}
return 0;
}