HDU 3642 Get The Treasury 【线段树+扫描线(相交体积)】

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

题目要求的是覆盖超过2次的总体积。

线段相交的长度,面相交的面积,物体相交的体积,这三种类型题使用的线段树方法都是差不多的。唯一不同的就是扫描线的扫描方式,这里求相交体积最重要的部分就是怎么扫才比较合适。

网上大部分都是以Z轴,也就是从下到上的顺序扫描的,只要离散化过后,从下到上,从左到右都行,时间都是足够的。

我们以面为单位,也就是扫描面,从左向右扫,但是并不是每一个面都是单独扫,假设我第一步扫最左边第一个面,求出覆盖超过2次的面积,如果有就乘以下一个扫描面的距离差,下一步再扫第二个面,但是并不是单单只扫这个面,还应该把第一个面叠加到第二个面,求这个叠加面覆盖超过2次的面积乘以下一个扫描面的距离差,同理扫描第三个面的时候,需要把第一个和第二个面叠加到第三个面。

下面是代码,代码没有简化,最好根据上面的思路自己写一下。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <set>
#include <queue>

using namespace std;

#define lc (cur<<1)
#define rc ((cur<<1)|1)

const int Maxn = 1000+10;
const int mod = 10007;
const int INF = 0x3f3f3f3f;

typedef long long ll;

struct tree {
    int cover, len1, len2, len3;
} seg[Maxn<<4];

struct Edge {
    int l ,r, val, xod, zod, ed;
    bool operator < (const Edge &a1) const {
        return zod < a1.zod;
    }
} edge[Maxn<<1];

int L, R, op, tmp[Maxn<<2], X[Maxn<<2], Z[Maxn<<2], Hash[Maxn<<2], tp[Maxn*6];

void pushup(int cur, int l, int r) {
    if(seg[cur].cover > 2) {
        seg[cur].len3 = Hash[r]-Hash[l-1];
        seg[cur].len2 = seg[cur].len1 = 0;
    }
    else if(seg[cur].cover == 2) {
        if(l == r) {
            seg[cur].len2 = Hash[r]-Hash[l-1];
            seg[cur].len1 = seg[cur].len3 = 0;
        } else {
            seg[cur].len3 = seg[lc].len1+seg[rc].len1
                                +seg[lc].len2+seg[rc].len2
                                    +seg[lc].len3+seg[rc].len3;
            seg[cur].len2 = Hash[r]-Hash[l-1]-seg[cur].len3;
            seg[cur].len1 = 0;
        }
    }
    else if(seg[cur].cover == 1) {
        if(l == r) {
            seg[cur].len1 = Hash[r]-Hash[l-1];
            seg[cur].len2 = seg[cur].len3 = 0;
        } else {
            seg[cur].len3 = seg[lc].len3+seg[rc].len3
                                +seg[lc].len2+seg[rc].len2;
            seg[cur].len2 = seg[lc].len1+seg[rc].len1;
            seg[cur].len1 = Hash[r]-Hash[l-1]-seg[cur].len3-seg[cur].len2;
        }
    }
    else {
        if(l == r) seg[cur].len1 = seg[cur].len2 = seg[cur].len3 = 0;
        else {
            seg[cur].len1 = seg[lc].len1+seg[rc].len1;
            seg[cur].len2 = seg[lc].len2+seg[rc].len2;
            seg[cur].len3 = seg[lc].len3+seg[rc].len3;
        }
    }
}

void updata(int cur, int l, int r) {
    if(L <= l && r <= R) {
        seg[cur].cover += op;
        pushup(cur, l, r);
        return;
    }

    int mid = (l+r)>>1;

    if(L <= mid) updata(lc, l, mid);
    if(mid+1 <= R) updata(rc, mid+1, r);

    pushup(cur, l, r);
}

int main(void)
{
    int T, N;
    scanf("%d", &T);
    for(int cas = 1; cas <= T; ++cas) {
        scanf("%d", &N);
        int m = 0, m1 = 0, m2 = 0, maxny = 0;
        for(int i = 0; i < N*6; i += 3) {
            scanf("%d%d%d", &tp[i], &tp[i+1], &tp[i+2]);
            Hash[m++] = tp[i];
            Hash[m++] = tp[i+1];
        }
        sort(Hash, Hash+m); m = unique(Hash, Hash+m)-Hash;

        int x1, x2, y1, y2, z1, z2;
        for(int i = 0; i < N; ++i) {
            x1 = lower_bound(Hash, Hash+m, tp[i*6])-Hash;
            y1 = lower_bound(Hash, Hash+m, tp[i*6+1])-Hash;
            x2 = lower_bound(Hash, Hash+m, tp[i*6+3])-Hash;
            y2 = lower_bound(Hash, Hash+m, tp[i*6+4])-Hash;
            z1 = tp[i*6+2]; z2 = tp[i*6+5];

            tmp[m1++] = x1; tmp[m1++] = x2;
            edge[++m2].l = y1+1; edge[m2].r = y2; edge[m2].xod = x1; edge[m2].zod = z1; edge[m2].val = 1; edge[m2].ed = x2;
            edge[++m2].l = y1+1; edge[m2].r = y2; edge[m2].xod = x1; edge[m2].zod = z2; edge[m2].val = -1; edge[m2].ed = x2;
            maxny = max(maxny, y1); maxny = max(maxny, y2);
        }

        sort(tmp, tmp+m1); m1 = unique(tmp, tmp+m1)-tmp;
        sort(edge+1, edge+m2+1);

        memset(X, 0, sizeof(X));

        for(int i = 0; i < m1-1; ++i) X[tmp[i]] = tmp[i+1]; // X存的是x轴相邻的x坐标
        for(int i = 0; i < (N<<3); ++i) seg[i].cover = seg[i].len1 = seg[i].len2 = seg[i].len3 = 0; // 树初始化

        ll ans = 0, area; int cnt, pos;

        printf("Case %d: ", cas);
        for(int i = 0; i < m1-1; ++i) { // x轴
            cnt = 0;
            for(int j = 1; j <= m2; ++j) {
                if(edge[j].xod <= tmp[i] && edge[j].ed > tmp[i]) tp[cnt++] = j;
            }
            area = 0;
            for(int j = 0; j < cnt; ++j) {
                L = edge[tp[j]].l; R = edge[tp[j]].r;
                op = edge[tp[j]].val;
                updata(1, 1, maxny);
                if(j+1 < cnt)
                    area += (ll)seg[1].len3*(edge[tp[j+1]].zod-edge[tp[j]].zod);
            }
            ans += area*(Hash[tmp[i+1]]-Hash[tmp[i]]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值