HDU - 4419 Colourful Rectangle【扫描线.笔记】

↘锁芯ラ 提交于 2020-01-23 02:36:09

题目链接:http://acm.hdu.edu.cn/viewcode.php?rid=32159923
题目大意:有n个矩形块,这些矩形块有R, G, B三种不同的颜色,最终区域的颜色由该区域上颜色的种类决定,要求输出 R, G, B, RG, RB, GB, RGB七种颜色的面积是多少。

思路:在前面区域覆盖面积的例题里,我们用一维数组维护被覆盖的区间长度,因为这里有颜色之分,所以可以再开一维表示颜色。此外,区域的颜色是由不同颜色的种类决定的,所以颜色的判断就可以很好地利用到或运算。

  • (扫描线中为什么不用push_down)扫描线的例题中利用了线段树这种数据结构,但是我们每次查询的都是整体,没有去询问某个子区间,所以不用push_down。

AC1:
//cover[root][i]表示区间被第i种颜色覆盖的次数

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define mid ((l + r)>>1)
#define chl root<<1
#define chr root<<1|1
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int manx=2e4+10;
int sum[manx<<3][8],cover[manx<<3][3],X[manx<<1],n;
struct node
{
    int y,lx,rx,color;
    int val;
    friend bool operator<(node a,node b)
    {
        return a.y<b.y;
    }
}line[manx<<1];
void init()
{
    memset(sum,0,sizeof(sum));
    memset(cover,0,sizeof(cover));
}
void eval(int root,int l,int r)
{
    int white=X[r+1]-X[l],Color=0;
    for(int i=0; i<=2; i++)
        if(cover[root][i])
            Color|=(1<<i);
    for(int i=1; i<=7; i++)
        sum[root][i]=0;
    for(int i=1; i<=7; i++)
    {
        sum[root][i|Color]+=sum[chl][i]+sum[chr][i];
        white-=sum[chl][i]+sum[chr][i];
    }
    if(Color)
        sum[root][Color]+=white;
}
void change(int root,int l,int r,int ll,int rr,int color,int val)
{
    if(l==ll&&r==rr)
    {
        cover[root][color]+=val;
        eval(root,l,r);
        return;
    }
    if(rr<=mid)
        change(chl,l,mid,ll,rr,color,val);
    else if(ll>mid)
        change(chr,mid+1,r,ll,rr,color,val);
    else
    {
        change(chl,l,mid,ll,mid,color,val);
        change(chr,mid+1,r,mid+1,rr,color,val);
    }
    eval(root,l,r);
}
int main()
{
    int t,x1,y1,x2,y2,Cas=0;;
    char str[2];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        init();
        for(int i=1; i<=n; i++)
        {
            int color;
            scanf("%s%d%d%d%d",str,&x1,&y1,&x2,&y2);
            if(str[0]=='R')
                color=2;
            else if(str[0]=='G')
                color=1;
            else
                color=0;
            line[2*i]=node{y1,x1,x2,color,1};
            X[2*i]=x1;
            line[2*i-1]=node{y2,x1,x2,color,-1};
            X[2*i-1]=x2;
        }
        sort(line+1,line+2*n+1);
        sort(X+1,X+2*n+1);
        int cnt=unique(X+1,X+2*n+1)-X-1;
        LL ans[8]= {0};
        for(int i=1; i<2*n; i++)
        {
            int l=lower_bound(X+1,X+cnt+1,line[i].lx)-X;
            int r=lower_bound(X+1,X+cnt+1,line[i].rx)-X-1;
            int dy=line[i+1].y-line[i].y;
            change(1,1,cnt,l,r,line[i].color,line[i].val);
            for(int i=1; i<=7; i++)
                ans[i]+=(LL)sum[1][i]*(LL)dy;
        }
        printf("Case %d:\n",++Cas);
        printf("%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n",ans[4],ans[2],ans[1],ans[6],ans[5],ans[3],ans[7]);
    }
    return 0;
}

AC2:
记录一下当时找bug时的心情。。真的MLE到哭泣。
在这里插入图片描述
本来觉得找到了扫描线的快乐,后面把sum的第二维降到了7(sum[][7]),然后又试了下vector存数据,结果都超内存了,重要的是后面发现又是一个沙雕错误:把lower_bound里面的cnt写成了2*n
在这里插入图片描述
后面找博客还发现自己之前的思路有些复杂:cover可以只用记录三种颜色出现的次数,回溯更新覆盖区间长度时 再判断最终的颜色,这样cover的操作会简单很很很多

//cover[root][i]=1表示区间被i种颜色覆盖

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define mid ((l + r)>>1)
#define chl root<<1
#define chr root<<1|1
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int manx=2e4+10;
int sum[manx<<3][8],cover[manx<<3][8],X[manx<<1],n;
struct node
{
    int y,lx,rx,color;
    int val;
    friend bool operator<(node a,node b)
    {
        return a.y<b.y;
    }
}line[manx<<1];
void init()
{
    memset(sum,0,sizeof(sum));
    memset(cover,0,sizeof(cover));
    //for(int i=1; i<=(n<<4); i++)
    //    cover[i][0]=1;
}
void eval(int root,int l,int r)
{
    int white=X[r+1]-X[l],Color=0;
    for(int i=1; i<=7; i++)
        if(cover[root][i])
        {
            Color=max(Color,i);
        }

    for(int i=1; i<=7; i++)
        sum[root][i]=0;
    for(int i=1; i<=7; i++)
    {
        sum[root][i|Color]+=sum[chl][i]+sum[chr][i];
        white-=sum[chl][i]+sum[chr][i];
    }
    if(Color)
        sum[root][Color]+=white;
}
void change(int root,int l,int r,int ll,int rr,int color,int val)
{
    if(l==ll&&r==rr)
    {
        if(val==1)
        {
            int flag=0;
            for(int i=1; i<=7; i++)
                if(cover[root][i])
                {
                    flag=max(flag,i);
                }
            cover[root][(1<<color)]++;
            if(flag&&flag!=(1<<color))
                cover[root][flag|(1<<color)]=1;
        }
        else
        {
            cover[root][(1<<color)]--;
            if(!cover[root][(1<<color)])
                for(int i=1; i<=7; i++)
                    if((i&(1<<color))&&cover[root][i])//需要color色
                    {
                        cover[root][i]=0;
                        int temp=i-(1<<color);
                        if(temp!=1&&temp!=2&&temp!=4)
                            cover[root][temp]=1;
                    }
        }
        eval(root,l,r);
        return;
    }
    if(rr<=mid)
        change(chl,l,mid,ll,rr,color,val);
    else if(ll>mid)
        change(chr,mid+1,r,ll,rr,color,val);
    else
    {
        change(chl,l,mid,ll,mid,color,val);
        change(chr,mid+1,r,mid+1,rr,color,val);
    }
    eval(root,l,r);
}
int main()
{
    int t,x1,y1,x2,y2,Cas=0;;
    char str[2];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        init();
        for(int i=1; i<=n; i++)
        {
            int color;
            scanf("%s%d%d%d%d",str,&x1,&y1,&x2,&y2);
            if(str[0]=='R')
                color=2;
            else if(str[0]=='G')
                color=1;
            else
                color=0;
            line[2*i]=node{y1,x1,x2,color,1};
            X[2*i]=x1;
            line[2*i-1]=node{y2,x1,x2,color,-1};
            X[2*i-1]=x2;
        }
        sort(line+1,line+2*n+1);
        sort(X+1,X+2*n+1);
        int cnt=unique(X+1,X+2*n+1)-X-1;
        LL ans[8]= {0};
        for(int i=1; i<2*n; i++)
        {
            int l=lower_bound(X+1,X+cnt+1,line[i].lx)-X;
            int r=lower_bound(X+1,X+cnt+1,line[i].rx)-X-1;
            int dy=line[i+1].y-line[i].y;
            change(1,1,cnt,l,r,line[i].color,line[i].val);
            for(int i=1; i<=7; i++)
                ans[i]+=(LL)sum[1][i]*(LL)dy;
        }
        printf("Case %d:\n",++Cas);
        printf("%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n",ans[4],ans[2],ans[1],ans[6],ans[5],ans[3],ans[7]);
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!