链接Artwork
- 题目大意
给你一个n*m的格子,依次向其中放入q个线段,让你输出每放一个线段之后图中的连通分量有多少个
分析
逆向思维
先将所有线段放上去之后从最后一个依次取,每取一个用并查集维护连通分量的个数
代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long int
const int MAXN=1005;
int n,m,q;//n行m列
int ans[10005];//ans[i]保存第i次查询的结果
int cnt;
int grid[MAXN][MAXN];
int belong[MAXN][MAXN];//belong[x][y]表示格子(x,y)属于哪一个连通分量
bool bj[MAXN][MAXN];//bj[i][j]表示格子(i,j)是否被访问过
int belong_cnt;
int pa[MAXN*MAXN];//fa[i]表示格子i所属的类别
int Rank[MAXN*MAXN];
struct Line
{
int X1,Y1,X2,Y2;
Line(){}
Line(int x1,int z1,int x2,int z2) {X1=x1,Y1=z1,X2=x2,Y2=z2;}
}line[10005];
int line_cnt;
void Init()
{
cnt=0;
line_cnt=0;
belong_cnt=0;
memset(grid,0,sizeof(grid));
}
void In()
{
int X1,Y1,X2,Y2;
for(int i=1;i<=q;i++)
{
scanf("%d%d%d%d",&Y1,&X1,&Y2,&X2);//坐标系进行了一次变换
line[++line_cnt]=Line(X1,Y1,X2,Y2);
}
}
void Cover(int X1,int Y1,int X2,int Y2)//用线段覆盖grid
{
int min_x=min(X1,X2);int max_x=max(X1,X2);
int min_y=min(Y1,Y2);int max_y=max(Y1,Y2);
if(X1==X2)for(int j=min_y;j<=max_y;j++)grid[X1][j]++;
else if(Y1==Y2) for(int i=min_x;i<=max_x;i++)grid[i][Y1]++;
}
void Print_grid()
{
cout<for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cout<" ";
}
cout<int Find(int x)
{
return pa[x]==x ? x : x=Find(pa[x]);
}
void Union(int a,int b)
{
int xa=Find(a);
int xb=Find(b);
if(Rank[xa]>Rank[xb]){pa[xb]=xa;}//Rank优化,Rank表示树的深度
else
{
pa[xa]=xb;
if(Rank[xa]==Rank[xb])Rank[xb]++;
}
}
void Print_belong()
{
cout<for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cout<" ";
}
cout<bool Is_out(int x,int y)
{
if(x<1 || x>n || y<1 || y>m)return 1;
else return 0;
}
void dfs(int x,int y)
{
if(bj[x][y]==1 || grid[x][y]>0)return ;
belong[x][y]=belong_cnt;
bj[x][y]=1;
if(!Is_out(x-1,y))dfs(x-1,y);
if(!Is_out(x,y-1))dfs(x,y-1);
if(!Is_out(x+1,y))dfs(x+1,y);
if(!Is_out(x,y+1))dfs(x,y+1);
}
void Init_Work()//初始化每个格子属于哪一个连通分量
{
for(int i=1;i<=line_cnt;i++)
{
Cover(line[i].X1,line[i].Y1,line[i].X2,line[i].Y2);//用线段覆盖grid
}
//Print_grid();
memset(bj,0,sizeof(bj));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(bj[i][j]==0 && grid[i][j]==0)
{
belong[i][j]=(++belong_cnt);//新的一个连通分量
pa[belong_cnt]=belong_cnt;//初始化类别的父亲是自己
Rank[belong_cnt]=1;
dfs(i,j);
}
}
}
}
void Classify(int x,int y,int &classes)//对一个新的格子进行分类,cnt表示合并了几个类
{
belong[x][y]=0;//(x,y)格子应该归的类别
if(!Is_out(x-1,y) && belong[x-1][y]!=0)
{
if(belong[x][y]==0)belong[x][y]=pa[belong[x-1][y]];
else if(Find(belong[x][y])!=Find(belong[x-1][y])){Union(belong[x][y],belong[x-1][y]);classes--;}
}
if(!Is_out(x,y-1) && belong[x][y-1]!=0)
{
if(belong[x][y]==0)belong[x][y]=pa[belong[x][y-1]];
else if(Find(belong[x][y])!=Find(belong[x][y-1])){Union(belong[x][y],belong[x][y-1]);classes--;}
}
if(!Is_out(x+1,y) && belong[x+1][y]!=0)
{
if(belong[x][y]==0)belong[x][y]=pa[belong[x+1][y]];
else if(Find(belong[x][y])!=Find(belong[x+1][y])){Union(belong[x][y],belong[x+1][y]);classes--;}
}
if(!Is_out(x,y+1) && belong[x][y+1]!=0)
{
if(belong[x][y]==0)belong[x][y]=pa[belong[x][y+1]];
else if(Find(belong[x][y])!=Find(belong[x][y+1])){Union(belong[x][y],belong[x][y+1]);classes--;}
}
if(belong[x][y]==0)
{
belong[x][y]=++belong_cnt;
pa[belong_cnt]=belong_cnt;
Rank[belong_cnt]=1;
classes++;
}
}
void Work()
{
//Print_grid();
//Print_belong();
int classes=belong_cnt;
for(int k=line_cnt;k>=1;k--)
{
ans[k]=classes;
int X1=line[k].X1,Y1=line[k].Y1,X2=line[k].X2,Y2=line[k].Y2;
int min_x=min(X1,X2);int max_x=max(X1,X2);
int min_y=min(Y1,Y2);int max_y=max(Y1,Y2);
if(X1==X2)
{
for(int j=min_y;j<=max_y;j++)
{
grid[X1][j]--;
if(grid[X1][j]==0)Classify(X1,j,classes);
}
}
else if(Y1==Y2)
{
for(int i=min_x;i<=max_x;i++)
{
grid[i][Y1]--;
if(grid[i][Y1]==0)Classify(i,Y1,classes);
}
}
}
for(int i=1;i<=line_cnt;i++)
{
printf("%d\n",ans[i]);
}
}
int main()
{
while(scanf("%d%d%d",&m,&n,&q)!=EOF)//n行m列
{
Init();
In();
Init_Work();
Work();
}
return 0;
}
/*
4 6 5
2 2 2 6
1 3 4 3
2 5 3 5
4 6 4 6
1 6 4 6
*/