HDU 4419 Colourful Rectangle --离散化+线段树扫描线

题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积。

解法: 很容易想到线段树扫描线求矩形面积并,但是如何维护每种颜色的长度着实让我伤透了脑筋。后来看了一位朋友的题解,才幡然醒悟。

开始想到了用二进制表示颜色,R用001表示,G用010表示,B用100表示。那么就可以用十进制1~7表示7种不同颜色了。

维护 cov[rt][1~3] 表示此区间内3种原色各有多少个, Len[rt][i]表示每种颜色的长度。

重点是pushup的写法,详情见代码, 离散化什么还比较简单。

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#define lll __int64

using namespace std;

#define N 10107



lll Len[7*N][8];

int cov[7*N][4];



struct Line

{

    int y1,y2,x;

    int col;

}line[2*N];

int yy[2*N];



int cmp(Line ka,Line kb) { return ka.x < kb.x; }



void pushup(int l,int r,int rt)

{

    int state = 0;

    for(int i=1;i<=3;i++) if(cov[rt][i]) state |= (1<<(i-1));  //表示此区间内有的颜色

    for(int i=0;i<8;i++)  Len[rt][i] = 0;                      //加了一层,要重新算各个颜色的长度

    if(l+1 == r)                                               //叶子节点

    {

        Len[rt][state] = yy[r]-yy[l];                          //只有此颜色state,长度为yy[r]-yy[l]

        return;

    }

    for(int i=0;i<8;i++)                                       //否则使用下面的更新

        Len[rt][i|state] += Len[2*rt][i] + Len[2*rt+1][i];

}



void build(int l,int r,int rt)

{

    for(int i=1;i<=3;i++) cov[rt][i] = 0;

    for(int i=1;i<8;i++)  Len[rt][i] = 0;

    Len[rt][0] = yy[r]-yy[l];

    if(l == r-1) return;

    int mid = (l+r)/2;

    build(l,mid,2*rt);

    build(mid,r,2*rt+1);

}



void update(int l,int r,int aa,int bb,int cover,int rt)

{

    if(aa <= l && bb >= r)

    {

        if(cover > 0) cov[rt][cover]++;

        else          cov[rt][-cover]--;

        pushup(l,r,rt);

        return;

    }

    if(l+1 == r) return;

    int mid = (l+r)/2;

    if(aa <= mid)

        update(l,mid,aa,bb,cover,2*rt);

    if(bb > mid)

        update(mid,r,aa,bb,cover,2*rt+1);

    pushup(l,r,rt);

}



int main()

{

    int n,m,t,cs = 1,i,j;

    int x1,y1,x2,y2,c;

    char ss[4];

    scanf("%d",&t);

    while(t--)

    {

        m = 1;

        scanf("%d",&n);

        for(i=0;i<n;i++)

        {

            scanf("%s%d%d%d%d",ss,&x1,&y1,&x2,&y2);

            if(ss[0] == 'R')      c = 1;

            else if(ss[0] == 'G') c = 2;

            else                  c = 3;

            line[m].x = x1,line[m].y1 = y1,line[m].y2 = y2,line[m].col = c,yy[m++] = y1;

            line[m].x = x2,line[m].y1 = y1,line[m].y2 = y2,line[m].col = -c,yy[m++] = y2;

        }

        m--;

        sort(yy+1,yy+m+1);

        int cnt = 2;

        for(i=2;i<=m;i++)

        {

            if(yy[i] != yy[i-1])

                yy[cnt++] = yy[i];

        }

        cnt--;

        build(1,cnt,1);

        sort(line+1,line+m+1,cmp);

        lll ans[8];

        memset(ans,0,sizeof(ans));

        printf("Case %d:\n",cs++);

        for(i=1;i<m;i++)

        {

            int L = lower_bound(yy+1,yy+cnt+1,line[i].y1)-yy;

            int R = upper_bound(yy+1,yy+cnt+1,line[i].y2)-yy-1;

            update(1,cnt,L,R,line[i].col,1);

            for(j=1;j<8;j++)

                ans[j] += Len[1][j]*(line[i+1].x-line[i].x);

        }

        printf("%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n%I64d\n",ans[1],ans[2],ans[4],ans[3],ans[5],ans[6],ans[7]);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(HDU)