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

本文介绍了一种解决三维空间中物体相交体积问题的算法,使用线段树方法进行求解,通过从左向右扫描面的方式,叠加前面的面来求得覆盖超过两次的总体积,适用于ACM竞赛中的特定问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: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;
}

 

一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值