A .Artwork
pro:给定N*M的白色格子,然后Q次黑棒,输出每次加黑棒后白色连通块的数量。(N,M<1e3, Q<1e4)
sol:倒着离线做,并查集即可。
(在线做法:https://www.cnblogs.com/asdfsag/p/10485607.html
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn = 1e6 + 10; int a[1010][1010], fa[maxn], ID[1010][1010]; struct node { int x1, y1, x2, y2; node(){} node(int x1, int y1, int x2, int y2):x1(x1), y1(y1), x2(x2), y2(y2){} }c[maxn]; int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);} int dir[][2] = {1,0,0,1,-1,0,0,-1}; stack<int>s; int main() { int n, m, q, tot = 0, x1, y1, x2, y2; scanf("%d%d%d", &n, &m, &q); for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){ID[i][j] = ++tot; fa[tot] = tot;} for(int i = 1; i <= q; i++) { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); c[i] = node(x1, y1, x2, y2); for(int x = x1; x <= x2; x++)for(int y = y1; y <= y2; y++)a[x][y]++; } int white = 0, cnt = 0; for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)if(!a[i][j]) { white++; for(int k = 0; k < 4; k++) { int x = i + dir[k][0], y = j + dir[k][1]; if(x >= 1 && x <= n && y >= 1 && y <= m && !a[x][y]) { int u = ID[i][j], v = ID[x][y]; u = Find(u);v = Find(v); if(u != v)fa[u] = v, cnt++; } } } s.push(white - cnt); for(int i = q; i >= 2; i--) { for(int x = c[i].x1; x <= c[i].x2; x++) for(int y = c[i].y1; y <= c[i].y2; y++) { a[x][y]--; if(!a[x][y]) { white++; for(int k = 0; k < 4; k++) { int xx = x + dir[k][0], yy = y + dir[k][1]; if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && !a[xx][yy]) { int u = ID[x][y], v = ID[xx][yy]; u = Find(u);v = Find(v); if(u != v)fa[u] = v, cnt++; } } } } s.push(white - cnt); } while(!s.empty()){cout<<s.top()<<endl;s.pop();} return 0; }