链接:点击打开链接
题意:画直线分区域,问每画完一条线有几个区域
思路:倒着做变成擦直线,合并区域或形成新区域。可以使用并查集来维护。启发:类似拆分的问题都可以倒过来离线变成合并的问题。
代码:
#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
",a);
return 0;
}