Artwork Gym - 101550A(並查集)

在這裏插入圖片描述

題意:
n*m的白格子,每次將一些部分塗黑,求剩下幾個白格連通塊

思路:
假設是順序塗黑,然後問黑格子連通塊有多少個,那就是並查集裸題。

本題中順序考慮很難。考慮逆向,假設全部塗完了,對每個白格子再往周圍遍歷一次,用並查集將相鄰白格子連起來,Union操作成功一次,連通塊減少一個。就可以算出此時的白色連通塊。

然後刪除一個黑格子,實際上多了個白格子,算作多了個連通塊。然後再用這個白格子遍歷周圍白格子,進行Union操作,Union成功了連通塊減少一個。

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>

using namespace std;

typedef long long ll;

const int maxn = 10005;

vector<pair<int,int> >G[maxn];
vector<int>res;
int a[maxn][maxn],fa[1000005];
int dirx[] = {1,-1,0,0};
int diry[] = {0,0,1,-1};
int n,m,q;

int f(int x,int y) {
    return (x - 1) * m + y;
}

bool check(int x,int y) {
    if(x >= 1 && y >= 1 && x <= n && y <= m) return true;
    return false;
}

int findset(int x) {
    if(fa[x] == x) return x;
    return fa[x] = findset(fa[x]);
}

bool Union(int x,int y) {
    int rx = findset(x),ry = findset(y);
    if(rx != ry) {
        fa[rx] = ry;
        return true;
    }
    return false;
}

int main() {
    scanf("%d%d%d",&n,&m,&q);
    int ans = n * m;
    
    for(int i = 1;i <= n * m;i++) {
        fa[i] = i;
    }
    
    for(int i = 1;i <= q;i++) {
        int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        if(x1 == x2) {
            for(int j = y1;j <= y2;j++) {
                if(a[x1][j]) continue;
                a[x1][j] = 1;
                ans--;
                G[i].push_back({x1,j});
            }
        }
        else {
            for(int j = x1;j <= x2;j++) {
                if(a[j][y1]) continue;
                a[j][y1] = 1;
                ans--;
                G[i].push_back({j,y1});
            }
        }
    }
    
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= m;j++) {
            if(!a[i][j]) {
                for(int d = 0;d < 4;d++) {
                    int dx = dirx[d] + i;
                    int dy = diry[d] + j;
                    if(check(dx,dy) && (!a[dx][dy] && Union(f(i,j),f(dx,dy)))) {
                        ans--;
                    }
                }
            }
        }
    }
    
    for(int i = q;i >= 1;i--) {
        res.push_back(ans);
        for(int j = 0;j < G[i].size();j++) {
            int x = G[i][j].first,y = G[i][j].second;
            a[x][y] = 0;ans++;
            for(int d = 0;d < 4;d++) {
                int dx = x + dirx[d],dy = y + diry[d];
                if(check(dx,dy) && (!a[dx][dy] && Union(f(x,y),f(dx,dy)))) {
                    ans--;
                }
            }
        }
    }
    
    for(int i = res.size() - 1;i >= 0;i--) {
        printf("%d\n",res[i]);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章