計蒜客 A.Artwork 並查集+set
阿新 • • 發佈:2018-12-01
連結:點選開啟連結
題意:畫直線分割槽域,問每畫完一條線有幾個區域
思路:倒著做變成擦直線,合併區域或形成新區域。可以使用並查集來維護。啟發:類似拆分的問題都可以倒過來離線變成合並的問題。
程式碼:
#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; }