hdu 4419 线段树 离散化 扫描线

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4419

题目大意:给出红绿蓝三种颜色的矩形,这些颜色的矩形重叠在一起组合成其他的颜色(共7种),求各种颜色的面积。

方法:前面处理扫描线的操作都是很基本的操作,关键的操作是在往上更新的时候,首先在红绿蓝用1,2,4表示,然后再通过位运算可以算出组合成的其他颜色,更新关键操作是参考网上的神代码,具体看程序。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 20005
typedef __int64 LL;
struct Line
{
    LL xl, xr, y, tp;
    Line(){}
    Line(LL xl, LL xr, LL y, LL tp):
        xl(xl), xr(xr), y(y), tp(tp){}
    bool operator < (const Line& b)const
    {
        return y<b.y;
    }
}line[maxn];
LL X[maxn];
struct node
{
    LL l, r, vnl, vnr;
    LL tp[4], sum[8];
}v[maxn<<2];
void build(LL l, LL r, LL n)
{
    v[n].l = l, v[n].r = r;
    v[n].vnl = X[l], v[n].vnr = X[r];
    memset(v[n].tp, 0, sizeof(v[n].tp));
    memset(v[n].sum, 0, sizeof(v[n].sum));
    if (l+1==r)
        return;
    LL mid = (l+r) >> 1;
    build(l, mid, n<<1);
    build(mid, r, n<<1|1);
}
void pushup(int n)
{
    LL k = 0, R = 1, G = 2, B = 4;
    if (v[n].tp[1]>0)
        k|=R;
    if (v[n].tp[2]>0)
        k|=G;
    if (v[n].tp[3]>0)
        k|=B;
    memset(v[n].sum, 0, sizeof(v[n].sum));
    if (k)
    {
        v[n].sum[k] = v[n].vnr - v[n].vnl;
        if (v[n].l+1==v[n].r)
            return;
        for (LL i=1; i<8; i++)//关键地方在这里
        {
            if ((k|i)!=k)
            {
                LL temp = v[n<<1].sum[i] + v[n<<1|1].sum[i];
                v[n].sum[k] -= temp;
                v[n].sum[k|i] += temp;
            }
        }
    }
    else
    {
        for (int i=1; i<8; i++)
            v[n].sum[i] = v[n<<1].sum[i] + v[n<<1|1].sum[i];
    }
}
void update(LL l, LL r, LL n, LL tp)
{
    if (l<=v[n].vnl && v[n].vnr<=r)
    {
        if (tp<0)
            --v[n].tp[-tp];
        else
            ++v[n].tp[tp];
        pushup(n);
        return ;
    }
    LL mid = (v[n].l + v[n].r) >> 1;
    if (r<=X[mid])
        update(l, r, n<<1, tp);
    else if (l>=X[mid])
        update(l, r, n<<1|1, tp);
    else
    {
        update(l, X[mid], n<<1, tp);
        update(X[mid], r, n<<1|1, tp);
    }
    pushup(n);
}
int main()
{
    char str[5];
    LL ncase, n, ans[8];
    cin >> ncase;
    for (LL k=1; k<=ncase; k++)
    {
        cin >> n;
        LL num = 0;
        for (LL i=0; i<n; i++)
        {
            LL x1, y1, x2, y2, tp;
            cin >> str >> x1 >> y1 >> x2 >> y2;
            if (str[0]=='R')
                tp = 1;
            else if (str[0]=='G')
                tp = 2;
            else
                tp = 3;
            line[++num] = Line(x1, x2, y1, tp);
            X[num] = x1;
            line[++num] = Line(x1, x2, y2, -tp);
            X[num] = x2;
        }
        sort(X+1, X+num+1);
        sort(line+1, line+num+1);
        n = 1;
        for (LL i=2; i<=num; i++)
            if (X[i]!=X[i-1])
                X[++n] = X[i];
        memset(ans, 0, sizeof(ans));
        build(1, n, 1);
        for (LL i=1; i<num; ++i)
        {
            update(line[i].xl, line[i].xr, 1, line[i].tp);
            LL yy = (line[i+1].y - line[i].y);
            for (LL j=1; j<8; j++)
                ans[j] += v[1].sum[j] * yy;
        }
        LL h[8] = {0, 1, 2, 4, 3, 5, 6, 7};
        printf("Case %I64d:\n", k);
        for (LL i=1; i<8; i++)
            printf("%I64d\n", ans[h[i]]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值