zoukankan      html  css  js  c++  java
  • HDOJ 3642 Get The Treasury(扫描线 + 线段树 + 离散化 立方体的并)

    题意:

    给一些长方体,求这些长方体相交至少3次的体积的并。

    思路:

    1. 先注意到 z 的变化范围 0 - 500,于是可以先把 z 离散化再枚举 z 坐标的高度。

    2. 对于每一个 z[i] - z[i+1] 的高度,找出跨越这个长的立方体,然后根据面积的方法求出扫描线 >= 3 的个数。

    3. 因为题目最终要求至少相交 3 次体积的并,对于每个固定 z 区间,要求 x-y 平面面积重合度 >= 3 即可,设置了几组标记:

       a. cnt[] 表示整个区间已经被扫描线覆盖的次数: cnt[rt] = 1 表示区间被扫描线完整的覆盖了 1 次。 等于 2 和等于 3 都是一样的道理。

       b. once[] 表示区间内仅仅被 1 次覆盖的扫描线的长度,twice[] 表示区间内仅仅被 2 次覆盖的扫描线的长度。

       c. sum[] 表示区间最终被覆盖 >= 3 的扫描线长度,对于不同的 cnt[],sum[] once[] twice[] 都有不同的计算方法,具体见代码注释。

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define lhs l, m, rt << 1
    #define rhs m + 1, r, rt << 1 | 1
    
    const int maxn = 2222;
    int sum[maxn << 2], cnt[maxn << 2];
    int once[maxn << 2], twice[maxn << 2];
    int xcord[maxn], zcord[maxn];
    
    struct Cube 
    {
        int x1, y1, z1;
        int x2, y2, z2;
    } cube[maxn] ;
    
    struct Segment 
    {
        int l, r, h, v;
    
        Segment() { } 
        Segment(int _l, int _r, int _h, int _v)
            : l(_l), r(_r), h(_h), v(_v)  { }
    
        bool operator < (const Segment& other)
        {
            if (h == other.h)
                return v > other.v;
            else
                return h < other.h;
        }
    } seg[maxn] ; 
    
    void pushUp(int l, int r, int rt)
    {
        if (cnt[rt] >= 3)
        {
            sum[rt] = xcord[r + 1] - xcord[l];        // 表示整个区间已经被扫描线覆盖 3 次,sum[] 自然为区间长度
            once[rt] = twice[rt] = 0;             // once[], twice[] 都为 0 表示区间内没有仅覆盖 1 次或 2 次的扫描线
        }
        else if (cnt[rt] == 2)
        {
            sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];    
            sum[rt] += once[rt << 1] + once[rt << 1 | 1];  // 因为整个区间已经被扫描线覆盖 2 次,所以 once[] 一定要为 0 
            sum[rt] += twice[rt << 1] + twice[rt << 1 | 1];  // 由于线段树中 cnt[] 并不是更新到底的,所以 sum[] 要加上左右子区间 once[], twice[] 的值
            once[rt] = 0;
            twice[rt] = xcord[r + 1] - xcord[l] - sum[rt];
        }
        else if (cnt[rt] == 1)
        {
            sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
            sum[rt] += twice[rt << 1] + twice[rt << 1 | 1];
            twice[rt] = once[rt << 1] + once[rt << 1 | 1];
            once[rt] = xcord[r + 1] - xcord[l] - sum[rt] - twice[rt];
        }
        else if (cnt[rt] == 0)
        {
            sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
            once[rt] = once[rt << 1] + once[rt << 1 | 1];
            twice[rt] = twice[rt << 1] + twice[rt << 1 | 1];
        }
    }
    
    void update(int beg, int end, int value, int l, int r, int rt)
    {
        if (beg <= l && r <= end)
        {
            cnt[rt] += value;
            pushUp(l, r, rt);
            return ;
        }
        int m = (l + r) >> 1;
        if (beg <= m)
            update(beg, end, value, lhs);
        if (end > m)
            update(beg, end, value, rhs);
        pushUp(l, r, rt);
    }
    
    __int64 solve(int n)
    {
        __int64 ret = 0;
        int m = 0;
        for (int i = 0; i < n; ++i)
        {
            xcord[m] = cube[i].x1;
            zcord[m++] = cube[i].z1;
            xcord[m] = cube[i].x2;
            zcord[m++] = cube[i].z2;    
        }
        sort(xcord, xcord + m);
        sort(zcord, zcord + m);
    
        int xnum = unique(xcord, xcord + m) - xcord;
        int znum = unique(zcord, zcord + m) - zcord;
    
        for (int z = 0; z < znum - 1; ++z)
        {
            m = 0;
            for (int i = 0; i < n; ++i)
            {
                if (cube[i].z1 <= zcord[z] && zcord[z] < cube[i].z2)
                {
                    seg[m++] = Segment(cube[i].x1, cube[i].x2, cube[i].y1, 1);
                    seg[m++] = Segment(cube[i].x1, cube[i].x2, cube[i].y2, -1);
                }
            }
            sort(seg, seg + m);
    
            memset(sum, 0, sizeof(sum));
            memset(cnt, 0, sizeof(cnt));
            memset(once, 0, sizeof(once));
            memset(twice, 0, sizeof(twice));
    
            __int64 area = 0;
            for (int i = 0; i < m - 1; ++i)
            {
                int beg = lower_bound(xcord, xcord + xnum, seg[i].l) - xcord;
                int end = lower_bound(xcord, xcord + xnum, seg[i].r) - xcord;
                if (beg < end)
                    update(beg, end - 1, seg[i].v, 0, xnum - 1, 1);
                area += (__int64)sum[1] * (seg[i+1].h - seg[i].h);
            }
            ret += area * (__int64)(zcord[z+1] - zcord[z]);
        }
        return ret;
    }
    
    int main()
    {
        int n, cases, cc = 0;
        scanf("%d", &cases);
        while (cases--)
        {
            scanf("%d", &n);
            for (int i = 0; i < n; ++i)
            {
                scanf("%d %d %d", &cube[i].x1, &cube[i].y1, &cube[i].z1);
                scanf("%d %d %d", &cube[i].x2, &cube[i].y2, &cube[i].z2);
            }
    
            __int64 ret;
            if (n < 3)
                ret = 0;
            else
                ret = solve(n);
            printf("Case %d: %I64d\n", ++cc, ret);
        }
        return 0;
    }
  • 相关阅读:
    关于返回上一页功能
    Mybatis Update statement Date null
    SQLite reset password
    Bootstrap Validator使用特性,动态(Dynamic)添加的input的验证问题
    Eclipse使用Maven2的一次环境清理记录
    Server Tomcat v7.0 Server at localhost failed to start
    PowerShell一例
    Server Tomcat v7.0 Server at libra failed to start
    商标注册英语
    A glance for agile method
  • 原文地址:https://www.cnblogs.com/kedebug/p/2890373.html
Copyright © 2011-2022 走看看