SGU 177 Square

题意:给出一个n×n的矩阵,矩阵上每个格子最开始都是白色的,给出m个操作,每个操作会把一个矩形染成黑色或白色,问最后有多少个白的格子。

思路:这题让我不禁想起了poj 2528,这类的染色问题应该都能用并查集搞……从后往前处理操作,这样已经画过的地方就不会第二次被染色,然后把染过的标记一下,接下来就是用并查集把染过的“跳过去”就好了,在这个过程中统计一下染过的黑色格子的数量,用总量一减就OK了~不过按这题的数据量来看,线段树应该也是完全没问题的……
————————————————
版权声明:本文为CSDN博主「qian99」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qian99/article/details/17171575

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1000+10;
int parents[maxn][maxn];
bool vis[maxn][maxn];
int Find(int r,int x)
{
    return parents[r][x]==x?x:parents[r][x]=Find(r,parents[r][x]);
}
struct Paint
{
    int x1,y1,x2,y2;
    int colors;
    void readit()
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    }
    void change()
    {
        if(x1>x2) swap(x1,x2);
        if(y1>y2) swap(y1,y2);
    }
}paints[maxn*5];
int main()
{
 
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    char str[5];
    for(int i=0;i<m;++i)
    {
        paints[i].readit();
        paints[i].change();
        scanf("%s",str);
        if(str[0]=='b') paints[i].colors=1;
        else paints[i].colors=0;
    }
    for(int i=1;i<=n;++i)
      for(int j=1;j<=n;++j)
         parents[i][j]=j;
    memset(vis,0,sizeof(vis));
    int total=n*n;
    int now,f;
    for(int i=m-1;i>=0;--i)
    {
        for(int j=paints[i].x1;j<=paints[i].x2;++j)
        {
            now=paints[i].y1;
            while(now<=paints[i].y2)
            {
                f=Find(j,now);
                if(f==now&&!vis[j][now])
                {
                    vis[j][now]=true;
                    parents[j][now]=paints[i].y2;
                    if(paints[i].colors) total--;
                    now++;
 
                }
                else now=f+1;
            }
        }
    }
    printf("%d\n",total);
    return 0;
}

  Sol2:

倒着扫描每个矩形,处理每个矩形时,向后遍历判断后面的矩形是否与其重叠,重叠的话就分割冲若干种小的矩形继续处理,直到最后统计没有被覆盖的面积..实现直接看代码吧..

#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
typedef long long ll;
int n,m;
int x1[10020],x2[10020],y1[10020],y2[10020];
int col[10020];
char c[3];
int cnt;
void slove(int xs,int ys,int xt,int yt,int d,int c)
{

    while (((xs>=x2[d])||(xt<=x1[d])||(ys>=y2[d])||(yt<=y1[d]))&& d<=m)
    //如果左上角点所在行>=第D个矩形右下角,即在第D个矩形下方 
	// 右下角行<=第D个矩形左上角,即在其上方,后面两个同理 
	      d++;
    if (d==m+1)
    {
        if (c) 
		   cnt+=(yt-ys)*(xt-xs);
		    //出现了多少个黑色点 
        return;
    }
    if (xs<x1[d])
    {
        slove(xs,ys,x1[d],yt,d+1,c);
        xs=x1[d];
    }
    if (xt>x2[d])
    {
        slove(x2[d],ys,xt,yt,d+1,c);
        xt=x2[d];
    }
    if (ys<y1[d]) 
	    slove(xs,ys,xt,y1[d],d+1,c);
    if (yt>y2[d])
	     slove(xs,y2[d],xt,yt,d+1,c);
}
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    cnt=0;
    
    for (int i=1; i<=m; i++)
    {
        scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]);
        if (x1[i]>x2[i]) swap(x1[i],x2[i]);
        if (y1[i]>y2[i]) swap(y1[i],y2[i]);
        x2[i]++;
        y2[i]++;
        scanf("%s",c);
        if (c[0]=='b')
		   col[i]=1;
        else 
		    col[i]=0;
    }
    for (int i=m; i>=1; i--)
    {
        if (col[i])
        slove(x1[i],y1[i],x2[i],y2[i],i+1,1);
    }
    cout<<n*n-cnt<<endl;

    return 0;
}

  

posted @ 2021-03-31 11:31  我微笑不代表我快乐  阅读(54)  评论(0编辑  收藏  举报