1. 程式人生 > >計蒜客 A.Artwork 並查集+set

計蒜客 A.Artwork 並查集+set

連結:點選開啟連結

題意:畫直線分割槽域,問每畫完一條線有幾個區域

思路:倒著做變成擦直線,合併區域或形成新區域。可以使用並查集來維護。啟發:類似拆分的問題都可以倒過來離線變成合並的問題。

程式碼:

#include<bits/stdc++.h>
#define LL long long
#define PB push_back
#define pii pair<int,int>
#define MP make_pair
#define X first
#define Y second
using  namespace std;
typedef long long ll;
const int maxn=2e6+10;
pii f[10004],s[10004];
int mp[1005][1005];
int fa[maxn];
set<int> ST;
int fin(int x){
    if(fa[x]==x)return x;
    fa[x]=fin(fa[x]);
    return fa[x];
}

void combin(int x,int y){
    int fx=fin(x),fy=fin(y);
    if(fx!=fy){
        fa[fx]=fy;
        if(ST.find(fx)!=ST.end()){
            ST.erase(ST.find(fx));
        }
        ST.insert(fy);
    }
    return;
}

int hs(int x,int y){
    return x*1000+y-1;
}

void up(int xx,int yy){
    ST.insert(hs(xx,yy));
    if(mp[xx+1][yy]==0) combin(hs(xx,yy),hs(xx+1,yy));
    if(mp[xx-1][yy]==0) combin(hs(xx,yy),hs(xx-1,yy));
    if(mp[xx][yy+1]==0) combin(hs(xx,yy),hs(xx,yy+1));
    if(mp[xx][yy-1]==0) combin(hs(xx,yy),hs(xx,yy-1));
    if(fin(hs(xx,yy))!=hs(xx,yy)&&ST.find(hs(xx,yy))!=ST.end()) ST.erase(ST.find(hs(xx,yy)));
}

int main(){
    int n,m,q;
    scanf("%d%d%d",&n,&m,&q);
    for(int i=0;i<maxn;i++) fa[i]=i;
    for(int i=0;i<q;i++){
        scanf("%d%d%d%d",&f[i].X,&f[i].Y,&s[i].X,&s[i].Y);
        if(f[i].X==s[i].X){
            if(f[i].Y>s[i].Y) swap(s[i],f[i]);
            for(int j=f[i].Y;j<=s[i].Y;j++) ++mp[f[i].X][j];
        }
        else{
            if(f[i].X>s[i].X) swap(s[i],f[i]);
            for(int j=f[i].X;j<=s[i].X;j++) ++mp[j][f[i].Y];
        }
    }
    for(int i=0;i<=n+1;i++) mp[i][m+1]=mp[i][0]=1;
    for(int i=0;i<=m+1;i++) mp[n+1][i]=mp[0][i]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(mp[i][j]==0)up(i,j);
    vector<int> ans;
    for(int i=q-1;i>=0;i--){
        ans.PB(ST.size());
        if(f[i].X==s[i].X){
            if(f[i].Y>s[i].Y) swap(s[i],f[i]);
            for(int j=f[i].Y;j<=s[i].Y;j++){
                --mp[f[i].X][j];
                if(mp[f[i].X][j]==0) up(f[i].X,j);
            }
        }
        else{
            if(f[i].X>s[i].X) swap(s[i],f[i]);
            for(int j=f[i].X;j<=s[i].X;j++){
                --mp[j][f[i].Y];
                if(mp[j][f[i].Y]==0)up(j,f[i].Y);
            }
        }
    }
    reverse(ans.begin(),ans.end());
    for(int a:ans) printf("%d\n",a);
    return 0;
}