hdu 4056 Draw a Mess -并查集+滑动法

http://acm.hdu.edu.cn/showproblem.php?pid=4056


题意:给n*m的格点 (n=200,m=5e5)

q次操作,每次按 四个几何图形 的面积去覆盖格点 ,每个图形带有一个颜色C (q=5e5,C=[1-9])

问最后q次操作完成后,每种颜色的格子有多少个,输出9个数


可以知道,颜色会覆盖,因此,从最后面开始处理,如果当前要涂色的格子未涂色,则这个格子最终必定是当前要涂的色,同理如果当前格子已经有色,则需要忽略。


现在问题是怎么处理涂色操作?

   由于行很少,可以暴力按行涂色,也即把该几何图形要覆盖的每一行都遍历,对于每行,用并查集去维护一个 大小为M的列:


维护一个father数组,fa[x]指的是x这个位置起,到达下一个可被涂色的位置-1,

维护一个vis数组,vis[x]=1,表示该位置已经涂色,=0则未涂色


假如图形X在 第i行的涂色范围是第L列到第R列,则

l=max (l,0);
                r=min(r,m-1);
                int fx=find(l);
                for (int i=r; i>=l;)
                {
                    int fy=find(i);<span style="white-space:pre">		</span>//找到最左的可涂色位置
                    if (!vis[fy]) ans[col]++;<span style="white-space:pre">			</span>//可涂色
                    vis[fy]=1;<span style="white-space:pre">					</span>//标记已涂色
                    if (fx!=fy) fa[fy]=fx;<span style="white-space:pre">			</span>//更新 【最左可涂色位置】
                    i=fy-1;<span style="white-space:pre">						</span>//继续滑动
                }



#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const double pi=acos(-1.0);
double eps=0.000001;

int fa[51234];
int vis[51234];
int find(int x)
{
    if (fa[x]==x)
        return x;
    else return fa[x]=find(fa[x]);
}
struct node
{
    char op[12];
    int x,y,z,d;
    int e;
    node() {}
};

node tm[51234];
int ans[10];
int main()
{
    int n,m,k;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        memset(ans,0,sizeof ans);
        for (int i=1; i<=k; i++)
        {
            scanf("%s%d%d%d%d",tm[i].op,&tm[i].x,&tm[i].y,&tm[i].z,&tm[i].d);
            if (tm[i].op[0]=='R') scanf("%d",&tm[i].e);
        }

        for (int j=0; j<n; j++)
        {
            for (int i=0; i<=m; i++) fa[i]=i,vis[i]=0;
            for (int i=k; i>=1; i--)
            {
                int l,r,col=tm[i].d;
                if (tm[i].op[0]=='C')
                {
                    int up=tm[i].x+tm[i].z;
                    int down=tm[i].x-tm[i].z;
                    if (!(j>=down&&j<=up ))continue;
                    int tmp=tm[i].z*tm[i].z-(tm[i].x-j)*(tm[i].x-j);
                    tmp=sqrt(tmp);
                    l=tm[i].y-tmp;
                    r=tm[i].y+tmp;
                }
                if (tm[i].op[0]=='D')
                {
                    int up=tm[i].x+tm[i].z;
                    int down=tm[i].x-tm[i].z;
                    if (!(j>=down&&j<=up ))continue;
                    l=tm[i].z-abs(j-tm[i].x);
                    r=tm[i].y+l;
                    l=tm[i].y-l;
                }
                if (tm[i].op[0]=='R')
                {
                    col=tm[i].e;
                    int up=tm[i].x+tm[i].z-1;
                    int down=tm[i].x;
                    if (!(j>=down&&j<=up ))continue;
                    l=tm[i].y;
                    r=tm[i].y+tm[i].d-1;
                }
                if (tm[i].op[0]=='T')
                {
                    int up=tm[i].x+(tm[i].z+1)/2-1;
                    int down=tm[i].x;
                    if (!(j>=down&&j<=up ))continue;
                    int tmp=(tm[i].z-1)/2+(tm[i].x-j);
                    l=tm[i].y-tmp;
                    r=tm[i].y+tmp;
                }
                l=max (l,0);
                r=min(r,m-1);
                int fx=find(l);
                for (int i=r; i>=l;)
                {
                    int fy=find(i);
                    if (!vis[fy]) ans[col]++;
                    vis[fy]=1;
                    if (fx!=fy) fa[fy]=fx;
                    i=fy-1;
                }
            }
        }
        for (int i=1; i<=9; i++)
        {
            if (i>1) printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");


    }


    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值