题意:给出一个n*m的方格,刚开始全是白色的方格,每次查询把一块区域染成黑色,问白色连通块的数目有多少
分析:用离线的方法来做,从后往前推的答案,联通块用并查集判断。
代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <string>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define lowbit(x) (x&(-x))
#define mem(a,b) memset(a,b,sizeof(a))
#define FRER() freopen("in.txt","r",stdin);
#define FREW() freopen("out.txt","w",stdout);
using namespace std;
const int maxn = 1000 + 7;
int n,m,q,num;
int a[maxn][maxn],f[maxn*maxn],X1[maxn*10],X2[maxn*10],Y1[maxn*10],Y2[maxn*10],res[maxn*10];
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
bool ok(int x,int y){
if(1<=x&&x<=n&&1<=y&&y<=m) return true;
return false;
}
int getid(int x,int y){
return (x-1)*m+y;
}
int Find(int u){
return u==f[u]?u:f[u] = Find(f[u]);
}
void unite(int x,int y){
//cout<<x<<" "<<y<<endl;
int xx = Find(x) , yy = Find(y);
if(xx!=yy){
f[xx] = yy;
num--;
}
}
void init(){
for(int i=0;i<=n*m;i++)
f[i] = i;
memset(a, 0, sizeof(a));
}
void dfs(int x,int y){
for(int i=0;i<4;i++){
int xx = x+dx[i];
int yy = y+dy[i];
if(ok(xx, yy)&&!a[xx][yy]){
unite(getid(x, y), getid(xx, yy));
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&q);
init();
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])
dfs(i,j);
else num--;
}
}
for(int i=q;i>=1;i--){
res[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++;
dfs(X1[i], j);
}
}else{
for(int j=X1[i];j<=X2[i];j++){
a[j][Y1[i]]--;
if(a[j][Y1[i]]) continue;
num++;
dfs(j, Y1[i]);
}
}
}
for(int i=1;i<=q;i++)
printf("%d\n",res[i]);
}