1. 程式人生 > >ArtWork (並查集 處理 方格陣的連通塊數量)

ArtWork (並查集 處理 方格陣的連通塊數量)

3030: ArtWork

時間限制: 4 Sec  記憶體限制: 128 MB
提交: 43  解決: 17
[提交] [狀態] [討論版] [命題人:外部匯入]

題目描述

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 (x 1 , y 1 ), ends at square (x 2 , y 2 ) (x 1 = x 2 or y 1 = y 2 ) and changes the color of all squares (x, y) to black where
x 1 ≤ x ≤ x 2 and y 1 ≤ y ≤ y 2 .

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.

輸入

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 integers x 1 , y 1 , x 2 and y 2 (1 ≤ x 1 ≤ x 2 ≤ n, 1 ≤ y 1 ≤ y 2 ≤ m). Either x 1 = x 2 or y 1 = y 2 (or both).

輸出

For each of the q strokes, output a line containing the beauty of the artwork after the stroke.

樣例輸入

4 6 5
2 2 2 6
1 3 4 3
2 5 3 5
4 6 4 6
1 6 4 6

樣例輸出

1
3
3
4
3

來源/分類

[提交] [狀態]

【題意】

n*m的方格陣,每次可以將一個黑條蓋在某一個子矩陣上,保證這個子矩陣窄邊為1。每次放上一個黑條後,輸出從未被覆蓋的格子的連通塊數量。

【分析】

考慮並查集維護連通塊,為了靠攏並查集的性質,我們把問題逆向思考,從最後的狀態開始一個個的揭開黑條。暴力揭即可。

每揭開一個格子,若為空白,暫時先認為出現了一個新連通塊,然後考慮去和它四周的空白格子去合併,若合併成功則連通塊數量-1

【程式碼】

#include<bits/stdc++.h>
using namespace std;

const int dir[4][2]={0,1,0,-1,-1,0,1,0};
int mmp[1010][1010],n,m,q,x[10010][2],y[10010][2],ans[10100];
int fa[1010101];
int father(int x){return x==fa[x]?x:fa[x]=father(fa[x]);}
bool join(int x,int y){x=father(x);y=father(y);if(x!=y)return fa[x]=y,true;return false;}
bool vis[1010][1010];
int gid(int x,int y){return (x-1)*m+y;}
void dfs(int x,int y,int dad)
{
    if(vis[x][y])return;
    vis[x][y]=true;
    fa[gid(x,y)]=dad;
    for(int i=0;i<4;i++)
    {
        int dx=x+dir[i][0], dy=y+dir[i][1];
        if(dx<1||dy<1||dx>n||dy>m||mmp[dx][dy])continue;
        dfs(dx,dy,dad);
    }
}
void fuck(int x,int y,int &sig)
{
    sig++; //當前是一個空白格子
    for(int i=0;i<4;i++)
    {
        int dx=x+dir[i][0], dy=y+dir[i][1];
        if(dx<1||dy<1||dx>n||dy>m||mmp[dx][dy])continue;
        if(join(gid(x,y),gid(dx,dy)))sig--;  //與鄰近的空白融合了
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=0;i<q;i++)
    {
        scanf("%d%d%d%d",&x[i][0],&y[i][0],&x[i][1],&y[i][1]);
        if(x[i][0]==x[i][1])
        {
            if(y[i][0]>y[i][1])swap(y[i][0],y[i][1]);
            for(int j=y[i][0];j<=y[i][1];j++)
                mmp[x[i][0]][j]++;
        }
        else if(y[i][0]==y[i][1])
        {
            if(x[i][0]>x[i][1])swap(x[i][0],x[i][1]);
            for(int j=x[i][0];j<=x[i][1];j++)
                mmp[j][y[i][0]]++;
        }
    }
    for(int i=n*m;i;i--)fa[i]=i;
    int sig=0;
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(!mmp[i][j]&&!vis[i][j])
        dfs(i,j,gid(i,j)),++sig;
    for(int i=q-1;~i;i--)
    {
        ans[i]=sig;
        if(x[i][0]==x[i][1])
        {
            for(int j=y[i][0];j<=y[i][1];j++)
                if(--mmp[x[i][0]][j]==0)fuck(x[i][0],j,sig);
        }
        else
        {
            for(int j=x[i][0];j<=x[i][1];j++)
                if(--mmp[j][y[i][0]]==0)fuck(j,y[i][0],sig);
        }
    }
    for(int i=0;i<q;i++)printf("%d\n",ans[i]);
}