• UVA 1493 Draw a Mess(并查集+set)


    这题我一直觉得使用了set这个大杀器就可以很快的过了,但是网上居然有更好的解法,orz。。。 
    题意:给你一个最大200行50000列的墙,初始化上面没有颜色,接着在上面可能涂四种类型的形状(填充): 
    圆 :给你圆心坐标,半径,颜色 (1->9) 
    菱形 :中心坐标,中心向四方的最大值,颜色(1->9) 
    矩形 :左上角坐标,长和宽,颜色(1->9) 
    等腰三角形:底边中心坐标,底边长(+1再/2 就是高),颜色(1->9) 
    其中输入的坐标一定在墙上,但是其他地方可能越界,所以要处理好。 
    最后输出每种颜色的个数

    开始觉得就是一个比较麻烦的暴力嘛,但是一看数据5000个询问。。。好吧想想优化。 
    我发现虽然总个数特别的多,但是如果我们把每次已经涂色的地方记录下来,下次不用寻找,这样就节约时间了。诶,等等,不对呀,不是前者要覆盖后者吗?所以我们要离线处理倒序涂色。 
    然后我们可以看到,行列分配得不均匀,如果我们枚举列话还是会超时(每次图形都列很多的情况)。所以我们枚举行,初始每行都使用一个并查集连接右边一个没被涂色的列。涂色后就把前面最后一个没涂色的连上后面最前一个没涂色的(前后都多加一个,避免特判),这样下次就可以不找这一段了,但是我们寻找最前面一个在图形范围内没涂色时又有可能会超时。所以我们上set:添加删除数据O(log2n),查询大于等于关键字的位置又是O(log2n)。每个图形找到涂色行中列的范围,使用set查询范围内最前面的一个,然后使用枚举没有涂色的列,注意这儿每次枚举后set内都要删除。 
    还有就是这题坑死了,三角形的底边长居然没按照题意,存在偶数。。。 

    代码比较挫

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define eps 1E-8
    /*注意可能会有输出-0.000*/
    #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
    #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
    #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
    #define mul(a,b) (a<<b)
    #define dir(a,b) (a>>b)
    typedef long long ll;
    typedef unsigned long long ull;
    const int Inf=1<<28;
    const double Pi=acos(-1.0);
    const int Mod=1e9+7;
    const int Max=50010;
    set<int> se[205];//每行建立一个set查询
    set<int>::iterator it;
    int fat[210][Max],ans[10];
    struct node
    {
        int xx1,yy1,l,w,c;
        char str[12];
    } blo[Max];
    void Init(int n,int m)
    {
        memset(ans,0,sizeof(ans));
        for(int i=0; i<=n+1; ++i)
        {
            se[i].clear();
            for(int j=0; j<=m+1; ++j)
            {
                se[i].insert(j);
                fat[i][j]=j+1;//初始化每行每个点指向下一个点,多加两个点避免边界特殊处理
            }
            fat[i][m+1]=m+1;
        }
        return;
    }
    int nmax(int a,int b)
    {
        return a>b?a:b;
    }
    int nmin(int a,int b)
    {
        return a>b?b:a;
    }
    int stax,ennx,stay,enny,tem;
    void Crc(int n,int m,node &p,int i)//
    {
        tem=int(sqrt(double(p.w-i+p.xx1)*(p.w+i-p.xx1)));
        it=se[i].lower_bound(nmax(p.yy1-tem,1));
        --it;
        stay=*it;
        enny=nmin(tem+p.yy1,m)+1;
        return;
    }
    void Dam(int n,int m,node &p,int i)//菱形
    {
        tem=p.w-abs(p.xx1-i);
        it=se[i].lower_bound(nmax(p.yy1-tem,1));
        --it;
        stay=*it;
        enny=nmin(tem+p.yy1,m)+1;
        return;
    }
    void Rtg(int n,int m,node &p,int i)//矩形
    {
        it=se[i].lower_bound(nmax(p.yy1,1));
        --it;
        stay=*it;
        enny=nmin(p.w+p.yy1,m+1);
        return;
    }
    void Trg(int n,int m,node &p,int i,int pp)//三角形
    {
        tem=pp-(p.w+1)/2+1;
        it=se[i].lower_bound(nmax(p.yy1+tem,1));
        --it;
        stay=*it;
        enny=nmin(p.yy1-tem,m)+1;
        return;
    }
    void Solve(int n,int m,int q)
    {
        for(int i=q-1; i>=0; --i)
        {
            if(blo[i].str[0]=='C')
            {
                stax=nmax(blo[i].xx1-blo[i].w,1);
                ennx=nmin(blo[i].w+blo[i].xx1,n)+1;
            }
            else if(blo[i].str[0]=='D')
            {
                stax=nmax(blo[i].xx1-blo[i].w,1);
                ennx=nmin(blo[i].w+blo[i].xx1,n)+1;
            }
            else if(blo[i].str[0]=='R')
            {
                stax=blo[i].xx1;
                ennx=nmin(blo[i].xx1+blo[i].l,n+1);
            }
            else
            {
                stax=blo[i].xx1;
                ennx=nmin(blo[i].xx1+(blo[i].w+1)/2-1,n)+1;
            }
            int j;
            for(int ii=stax; ii<ennx; ++ii)
            {
                if(blo[i].str[0]=='C')
                    Crc(n,m,blo[i],ii);
                else if(blo[i].str[0]=='D')
                    Dam(n,m,blo[i],ii);
                else if(blo[i].str[0]=='R')
                    Rtg(n,m,blo[i],ii);
                else
                    Trg(n,m,blo[i],ii,ii-stax);
                j=fat[ii][stay];
                while(j<enny)
                {
                    se[ii].erase(j);
                    j=fat[ii][j];//并查集可以跳过已经涂色过的
                    ++ans[blo[i].c];
                    fat[ii][stay]=j;
                }
            }
        }
        return;
    }
    int main()
    {
        int n,m,q;
        while(~scanf("%d %d %d",&n,&m,&q))
        {
            Init(n,m);
            for(int i=0; i<q; ++i)
            {
                scanf("%s",blo[i].str);
                if(blo[i].str[0]=='R')
                    scanf("%d %d %d %d %d",&blo[i].xx1,&blo[i].yy1,&blo[i].l,&blo[i].w,&blo[i].c);
                else
                    scanf("%d %d %d %d",&blo[i].xx1,&blo[i].yy1,&blo[i].w,&blo[i].c);
                ++blo[i].xx1,++blo[i].yy1;
            }
            Solve(n,m,q);
            for(int i=1; i<10; i++)
                printf("%d%c",ans[i],i==9?'
    ':' ');
        }
        return 0;
    }
  • 相关阅读:
    天使投资家李镇樟:如何培养世界级企业家
    [案例分析] 打造值得信任的个人品牌究竟靠什么?
    怎能相逢
    企业的创新和创新的双面性
    给创业者的忠告:中国互联网的柏金森定律
    梦想的婚礼
    企业人,需守候精神商业的价值
    我与东方
    五种成功创业模式让你轻松赚到钱
    一招一式, 成就“霸业”必做的9件大事
  • 原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/5863755.html
Copyright © 2020-2023  润新知