NCPC 2016 A Artwork(并查集)

来源:互联网 发布:pc网络电视直播软件 编辑:程序博客网 时间:2024/05/16 15:01

链接Artwork
- 题目大意

给你一个n*m的格子,依次向其中放入q个线段,让你输出每放一个线段之后图中的连通分量有多少个

  • 分析
    逆向思维
    先将所有线段放上去之后从最后一个依次取,每取一个用并查集维护连通分量的个数

  • 代码

#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<cstdlib>#include<queue>#include<map>#include<algorithm>#include<set>#include<stack>using namespace std;#define  LL  long long intconst 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<<endl;    for(int i=1;i<=n;i++)    {        for(int j=1;j<=m;j++)        {            cout<<grid[i][j]<<" ";        }        cout<<endl;    }}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<<endl;    for(int i=1;i<=n;i++)    {        for(int j=1;j<=m;j++)        {            cout<<Find(belong[i][j])<<" ";        }        cout<<endl;    }}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 52 2 2 61 3 4 32 5 3 54 6 4 61 6 4 6*/
原创粉丝点击