1. 程式人生 > >csuoj2022-Artwork(並查集連通塊)

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

1 ≤ x ≤ x2 and y1 ≤ y ≤ y2. The beauty of an artwork is the number of regions in the grid. Each region consists of one or more white squares that are connected to each other using a path of white squares in the grid, walking horizontally or vertically but not diagonally. The initial beauty of the artwork is 1. Your task is to calculate the beauty after each new stroke. Figure A.1 illustrates how the beauty of the artwork varies in Sample Input 1.

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;
}