csuoj2022-Artwork(並查集連通塊)
Description
點選開啟題目連結A template for an artwork is a white grid of n × m squares. The artwork will be created by painting q horizontal and vertical black strokes. A stroke starts from square (x1, y1), ends at square (x2,y2)(x1=x2(x2,y2)(x1=x2 or y1=y2)y1=y2) and changes the color of all squares (x, y) to black where x
Input
The first line of input contains three integers n, m and q (1 ≤ n, m ≤ 1000, 1 ≤ q ≤ 104). Then follow q lines that describe the strokes. Each line consists of four integersx1,y1,x2x1,y1,x2 and y2(1 ≤ x1 ≤ x2 ≤ n, 1 ≤ y1 ≤ y2 ≤ m). Either x1 = x2 or y1=y2y1=y2(or both).
Output
For each of the q strokes, output a line containing the beauty of the artwork after the stroke.
Sample Input
4 6 5 2 2 2 6 1 3 4 3 2 5 3 5 4 6 4 6 1 6 4 6
Sample Output
1 3 3 4 3
Hint
Source
NCPC 2016
題目大意:給m*n的網格,q次操作和詢問,每次將兩個格子間的全部格子塗黑(只有豎直和水平兩種情況),然後詢問剩下的白色連通塊的個數思路分析:離線記錄每次操作,從末狀態倒跑回初始狀態,,用並查集記錄白塊的連通情況,每次判斷連通情況和修改連通塊的個數即可程式碼#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int A[1010][1010],n,m,p[1000010],B[10010],C[10010],D[10010],E[10010],dx[]={0,0,-1,1},dy[]={-1,1,0,0},cnt;
//A記錄每點塗黑的次數,B,C,D,E記錄每次操作時兩點的座標位置,cnt記錄連通塊數量
int find(int x){
if(x==p[x]) return x;
int k=find(p[x]);
p[x]=k;
return k;
}
void dfs(int x,int y,int k){ //末狀態時統計連通塊個數
p[m*(x-1)+y]=k;
int u,v,i;
for(i=0;i<=3;i++){
u=x+dx[i];
v=y+dy[i];
if(u>=1&u<=n&&v>=1&&v<=m&&A[u][v]==0&&p[m*(u-1)+v]==0) dfs(u,v,k);
}
}
void unio(int x,int y){
int i,u,v,f1,f2,flag=0;
p[m*(x-1)+y]=m*(x-1)+y;
cnt++; //合併操作,對於該點判斷是否和周圍四點連通,可以合併時聯通塊數量-1;
u=x+dx[i];
for(i=0;i<=3;i++){
v=y+dy[i];
if(u>=1&&v>=1&&u<=n&&v<=m&&!A[u][v]){
f1=find(m*(x-1)+y);
f2=find(m*(u-1)+v);
if(f1!=f2){
cnt--;
p[f2]=f1;
}
}
}
}
int main(){
int i,j,k,q,x1,y1,x2,y2,ans[10010];
scanf("%d%d%d",&m,&n,&q);
memset(A,0,sizeof(A));
memset(p,0,sizeof(p));
for(i=1;i<=q;i++){
scanf("%d%d%d%d",&y1,&x1,&y2,&x2);
B[i]=x1;
C[i]=y1;
D[i]=x2;
E[i]=y2;
if(x1==x2){
if(y1>y2) for(j=y2;j<=y1;j++) A[x1][j]++;
else for(j=y1;j<=y2;j++) A[x1][j]++;
}
else{
if(x1>x2) for(j=x2;j<=x1;j++) A[j][y1]++;
else for(j=x1;j<=x2;j++) A[j][y1]++;
}
}
cnt=0;
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(A[i][j]==0&&p[m*(i-1)+j]==0){
cnt++;
k=m*(i-1)+j;
dfs(i,j,k);
}
}
}
//倒跑合並過程
ans[q]=cnt;
for(i=q;i>=1;i--){
if(B[i]==D[i]){
if(C[i]>E[i]){
for(j=E[i];j<=C[i];j++){
A[B[i]][j]--;
if(A[B[i]][j]==0) unio(B[i],j);
}
}
else{
for(j=C[i];j<=E[i];j++){
A[B[i]][j]--;
if(A[B[i]][j]==0) unio(B[i],j);
}
}
}
else{
if(B[i]>D[i]){
for(j=D[i];j<=B[i];j++){
A[j][C[i]]--;
if(A[j][C[i]]==0) unio(j,C[i]);
}
}
else{
for(j=B[i];j<=D[i];j++){
A[j][C[i]]--;
if(A[j][C[i]]==0) unio(j,C[i]);
}
}
}
ans[i-1]=cnt;
}
for(i=1;i<=q;i++) cout<<ans[i]<<endl;
return 0;
}