hdu4419Colourful Rectangle(线段树+离散化+扫描线)

->题目请戳这里<-

题目大意:在二维平面内给n个矩形,矩形有3种颜色,不同颜色相交的部分就产生了不同的颜色,一共就有7种颜色。对于每个区域内的颜色与某中颜色覆盖的次数无关,只与覆盖的颜色种类有关,求最后这n个矩形相交产生7种颜色的面积。

题目分析:这题和这道hdu1255思路基本是一样的,不过1255求的是重复覆盖2+次面积并,情况简单些,这里3种颜色一交就会产生7种情况,分析就稍微复杂一点点。

下面简单分析下:

对于线段树节点的定义:我选择用2个数组保存信息,数组col表示当前节点被覆盖的颜色种类,col[1]表示覆盖颜色R,col[2]表示覆盖了颜色G,col[3]表示覆盖了颜色B;len表示当前区间7种颜色下的有效长度,len[1] - len[7]分别表示当前区间下R,G,B,RG,RB,GB,RGB这7种颜色的有效长度。

对于每个区域,如果当前区域是叶子节点,即不能再分成子区间了,那么这个区域只能有7种情况中的一种。直接根据覆盖的情况确定当前区间的有效长度。

如果当前区间不是叶子节点,那么就考虑当前区间的颜色覆盖情况:

1:如果当前区间3种颜色全部覆盖,那么这整个区间都是RGB,计算len[7];

2:如果当前区间覆盖了2种颜色,假设覆盖了RG,那么这个区间只可能有2种颜色,RGB和RG,至少是RG,那么先算RGB,当前区间的RGB就是左右子区间的RGB+左右子区间的B(想一想,为什么),当前区间的RG就是当前整个区间长度-RGB长度,其他2种当前区间恰好被2种颜色同时覆盖的情况类似;

3:如果当前区间恰好只覆盖了一种颜色,假设覆盖了R,那么当前区间颜色覆盖情况就有4种:R,RG,RB,RGB,先算RGB,长度就是左右子区间的RGB和左右子区间的GB长度之和,RG的长度就是左右子区间能提供G的长度之和,即左右子区间的G,RG,RB同理,R的长度就是剩下的长度了,这里一定要想清楚,其他还有2种情况也是类似的。

4:如果当前区间没有颜色恰好覆盖,那么直接将左右子区间的各种颜色相加即可。

废话就这么多了,详情请见代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10005;
char color[3];
int hash[N<<1];
__int64 ans[10];
struct node
{
    int x,y1,y2;
    int flag,c;
}line[N<<1];

struct nd
{
    int col[4];
    __int64 len[8];
}tree[N<<4];

int cmp(struct node a,struct node b)
{
    return a.x < b.x;
}

void build(int num,int s,int e)
{
    memset(tree[num].col,0,sizeof(tree[num].col));
    memset(tree[num].len,0,sizeof(tree[num].len));
    if(s == e)
        return;
    int mid = (s + e)>>1;
    build(num<<1,s,mid);
    build(num<<1|1,mid + 1,e);
}

void cal_len(int num,int s,int e)
{
    memset(tree[num].len,0,sizeof(tree[num].len));
    if(tree[num].col[1] && tree[num].col[2] && tree[num].col[3])
    {
        tree[num].len[7] = hash[e + 1] - hash[s];
        return;
    }
    if(tree[num].col[1] && tree[num].col[2])
    {
        tree[num].len[7] = tree[num<<1].len[7] + tree[num<<1|1].len[7] + tree[num<<1].len[3] + tree[num<<1|1].len[3];
        tree[num].len[7] += (tree[num<<1].len[5] + tree[num<<1|1].len[5] + tree[num<<1].len[6] + tree[num<<1|1].len[6]);
        tree[num].len[4] = hash[e + 1] - hash[s] - tree[num].len[7];
        return;
    }
    if(tree[num].col[1] && tree[num].col[3])
    {
        tree[num].len[7] = tree[num<<1].len[7] + tree[num<<1|1].len[7] + tree[num<<1].len[2] + tree[num<<1|1].len[2];
        tree[num].len[7] += (tree[num<<1].len[4] + tree[num<<1|1].len[4] + tree[num<<1].len[6] + tree[num<<1|1].len[6]);
        tree[num].len[5] = hash[e + 1] - hash[s] - tree[num].len[7];
        return;
    }
    if(tree[num].col[2] && tree[num].col[3])
    {
        tree[num].len[7] = tree[num<<1].len[7] + tree[num<<1|1].len[7] + tree[num<<1].len[1] + tree[num<<1|1].len[1];
        tree[num].len[7] += (tree[num<<1].len[5] + tree[num<<1|1].len[5] + tree[num<<1].len[4] + tree[num<<1|1].len[4]);
        tree[num].len[6] = hash[e + 1] - hash[s] - tree[num].len[7];
        return;
    }
    if(tree[num].col[1])
    {
        tree[num].len[7] = tree[num<<1].len[7] + tree[num<<1|1].len[7] + tree[num<<1].len[6] + tree[num<<1|1].len[6];
        tree[num].len[5] = tree[num<<1].len[5] + tree[num<<1|1].len[5] + tree[num<<1].len[3] + tree[num<<1|1].len[3];
        tree[num].len[4] = tree[num<<1].len[4] + tree[num<<1|1].len[4] + tree[num<<1].len[2] + tree[num<<1|1].len[2];
        tree[num].len[1] = hash[e + 1] - hash[s] - tree[num].len[4] - tree[num].len[5] - tree[num].len[7];
        return;
    }
    if(tree[num].col[2])
    {
        tree[num].len[7] = tree[num<<1].len[7] + tree[num<<1|1].len[7] + tree[num<<1].len[5] + tree[num<<1|1].len[5];
        tree[num].len[6] = tree[num<<1].len[6] + tree[num<<1|1].len[6] + tree[num<<1].len[3] + tree[num<<1|1].len[3];
        tree[num].len[4] = tree[num<<1].len[4] + tree[num<<1|1].len[4] + tree[num<<1].len[1] + tree[num<<1|1].len[1];
        tree[num].len[2] = hash[e + 1] - hash[s] - tree[num].len[4] - tree[num].len[6] - tree[num].len[7];
        return;
    }
    if(tree[num].col[3])
    {
        tree[num].len[7] = tree[num<<1].len[7] + tree[num<<1|1].len[7] + tree[num<<1].len[4] + tree[num<<1|1].len[4];
        tree[num].len[6] = tree[num<<1].len[6] + tree[num<<1|1].len[6] + tree[num<<1].len[2] + tree[num<<1|1].len[2];
        tree[num].len[5] = tree[num<<1].len[5] + tree[num<<1|1].len[5] + tree[num<<1].len[1] + tree[num<<1|1].len[1];
        tree[num].len[3] = hash[e + 1] - hash[s] - tree[num].len[6] - tree[num].len[5] - tree[num].len[7];
        return;
    }
    int i;//如果都不是,直接将左右子区间的合并
    for(i = 1;i <= 7;i ++)
        tree[num].len[i] = tree[num<<1].len[i] + tree[num<<1|1].len[i];
}

void insert(int num,int s,int e,int l,int r,int add,int kind)
{
    if(s == e)
    {
        tree[num].col[kind] += add;
        memset(tree[num].len,0,sizeof(tree[num].len));
        if(tree[num].col[1] && tree[num].col[2] && tree[num].col[3])
        {
            tree[num].len[7] = hash[e + 1] - hash[s];
            return;
        }
        if(tree[num].col[1] && tree[num].col[2])
        {
            tree[num].len[4] = hash[e + 1] - hash[s];
            return;
        }
        if(tree[num].col[1] && tree[num].col[3])
        {
            tree[num].len[5] = hash[e + 1] - hash[s];
            return;
        }
        if(tree[num].col[2] && tree[num].col[3])
        {
            tree[num].len[6] = hash[e + 1] - hash[s];
            return;
        }
        if(tree[num].col[1])
        {
            tree[num].len[1] = hash[e + 1] - hash[s];
            return;
        }
        if(tree[num].col[2])
        {
            tree[num].len[2] = hash[e + 1] - hash[s];
            return;
        }
        if(tree[num].col[3])
        {
            tree[num].len[3] = hash[e + 1] - hash[s];
            return;
        }
        return;
    }
    if(s == l && e == r)
    {
        tree[num].col[kind] += add;
        cal_len(num,s,e);
        return;
    }
    int mid = (s + e)>>1;
    if(r <= mid)
        insert(num<<1,s,mid,l,r,add,kind);
    else
    {
        if(l > mid)
            insert(num<<1|1,mid + 1,e,l,r,add,kind);
        else
        {
            insert(num<<1,s,mid,l,mid,add,kind);
            insert(num<<1|1,mid + 1,e,mid + 1,r,add,kind);
        }
    }
    cal_len(num,s,e);
}

int gety(int x,int len)
{
    int l = 1;
    int r = len;
    int mid;
    while(l <= r)
    {
        mid = (l + r)>>1;
        if(hash[mid] == x)
            return mid;
        else
        {
            if(hash[mid] > x)
                r = mid - 1;
            else
                l = mid + 1;
        }
    }
    return -1;
}

int main()
{
    int n,i,m;
    int cas = 0;
    int t;
    int x1,x2,y1,y2;
    scanf("%d",&t);
    while(t --)
    {
        scanf("%d",&n);
        for(i = 1;i < n + n;i += 2)
        {
            scanf("%s",color);
            int tt;
            if(color[0] == 'R')
                tt = 1;
            if(color[0] == 'G')
                tt = 2;
            if(color[0] == 'B')
                tt = 3;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            line[i].x = x1;
            line[i].y1 = y1;
            line[i].y2 = y2;
            line[i].flag = 1;
            line[i].c = tt;
            line[i + 1].c = tt;
            line[i + 1].x = x2;
            line[i + 1].y1 = y1;
            line[i + 1].y2 = y2;
            line[i + 1].flag = -1;
            hash[i] = y1;
            hash[i + 1] = y2;
        }
        m = 2;
        sort(hash + 1,hash + n + n + 1);
        for(i = 2;i <= n + n;i ++)//
            if(hash[i] != hash[i - 1])
                hash[m ++] = hash[i];
        m --;
        build(1,1,m);
        sort(line + 1,line + n + n + 1,cmp);
        int l,r;
        memset(ans,0,sizeof(ans));
        l = gety(line[1].y1,m);
        r = gety(line[1].y2,m) - 1;
        insert(1,1,m,l,r,line[1].flag,line[1].c);
        for(i = 2;i <= n + n;i ++)
        {
            __int64 w = line[i].x - line[i - 1].x;
            for(int j = 1;j <= 7;j ++)
                ans[j] += w * tree[1].len[j];
            l = gety(line[i].y1,m);
            r = gety(line[i].y2,m) - 1;
            insert(1,1,m,l,r,line[i].flag,line[i].c);
        }
        printf("Case %d:\n",++cas);
        for(i = 1;i <= 7;i ++)
            printf("%I64d\n",ans[i]);
    }
    return 0;
}
//218MS	3348K


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值