扫描线 体积交 -- Get The Treasury HDU - 3642

Get The Treasury HDU - 3642

题意:
求相交三次及以上的立方体体积。

思路:
由于z 最多只有1000层, 故我们可以直接对每一层求一次面积并。 但是求层数的时候有一个特别要注意的地方, 比如z包含 3 4 5这3层,算的时候我们求的是3层,实际上我们求体积只用求2层即可。故判断一下就行。这样若果只有一层 的话就不会算进去,因为一层构不成体积。 其他的就和基本的扫描线类似了。

code:

#include <cstdio>
#include <iostream>
#include <algorithm>
typedef long long ll;
using namespace std;
const int N = 2e4 + 5, M = 1005;
struct Line {
	int st;
	double s, e, x, z1, z2; //z1、z2记录这条线的范围 
	bool operator < (const Line & w) const {
		return x < w.x;
	}
} line[N];
struct Node {
	int cnt, len1, len2, len3;
} tr[N << 2];
int t, n, cnt, m, x1, x2, y1, y2, z1, z2, fy[N];
int find(int y) {
	return lower_bound(fy + 1, fy + 1 + cnt, y) - fy;
}
void pushup(int id, int l, int r) {
	if (tr[id].cnt){ // 代表id这个区间被覆盖了  
		tr[id].len1 = fy[r + 1] - fy[l]; //因为一个点代表的是一个区间 那r这个点的区间 就是[fy[r], fy[r + 1]]这段长度 
	} else if (l != r){ //如果这整个区间没有被包含 那么就由儿子区间组成 
		tr[id].len1 = tr[id << 1].len1 + tr[id << 1 | 1].len1; 
	} else tr[id].len1 = 0; //叶子结点  
	//当cnt >= 2的时候
	if (tr[id].cnt >= 2) {
		tr[id].len2 = fy[r + 1] - fy[l];
	} else if (l != r && tr[id].cnt == 1)  { //当cnt == 1的时候 子区间若被包含了一次那么加上父亲的一次就是2次了		
		tr[id].len2 = tr[id << 1].len1 + tr[id << 1 | 1].len1; 
	} else if (l != r){ //这种情况若不是根节点 那么便可以通过子节点的len2得来 
		tr[id].len2 = tr[id << 1].len2 + tr[id << 1 | 1].len2;   
	} else { //根节点 或者 不满足上面条件的都直接等于0 
		tr[id].len2 = 0;
	} 
	//当cnt >= 3的时候
	if (tr[id].cnt >= 3) {
		tr[id].len3 = fy[r + 1] - fy[l];
	} else if (l != r && tr[id].cnt == 2)  {  	
		tr[id].len3 = tr[id << 1].len1 + tr[id << 1 | 1].len1; 
	} else if (l != r && tr[id].cnt == 1)  {  	
		tr[id].len3 = tr[id << 1].len2 + tr[id << 1 | 1].len2; 
	} else if (l != r){ 
		tr[id].len3 = tr[id << 1].len3 + tr[id << 1 | 1].len3;   
	} else { 
		tr[id].len3 = 0;
	} 
}
void build(int id, int l, int  r) {
	tr[id].cnt = tr[id].len1 = tr[id].len2 = tr[id].len3 = 0;
	if (l == r) return;
	int mid = (l + r) >> 1;
	build(id << 1, l, mid);
	build(id << 1 | 1, mid + 1, r);
}
void update(int id, int l, int r, int x, int y, int d) {
	if (x <= l && r <= y) {
		tr[id].cnt += d;
		pushup(id, l, r);
		return;
	}
	int mid = (l + r) >> 1;
	if (x <= mid) update(id << 1, l, mid, x, y, d);
	if (y > mid) update(id << 1 | 1, mid + 1, r, x, y, d);
	pushup(id, l, r); 
}
int main() {
	scanf("%d", &t); 
	for (int ci = 1; ci <= t; ci++) {
		scanf("%d", &n);
		cnt = 0; //代表有多少个y点 
		for (int i = 1; i <= n; i++) {
			scanf("%d%d%d%d%d%d", &x1, &y1, &z1, &x2, &y2, &z2);
 			line[++cnt].s = y1; line[cnt].e = y2, line[cnt].x = x1, line[cnt].z1 = z1, line[cnt].z2 = z2, line[cnt].st = 1, fy[cnt] = y1; 
 			line[++cnt].s = y1; line[cnt].e = y2, line[cnt].x = x2, line[cnt].z1 = z1, line[cnt].z2 = z2, line[cnt].st = -1, fy[cnt] = y2; 
		} 
		//对y坐标进行离散化 
		sort(fy + 1, fy + 1 + cnt);
		sort(line + 1, line + 1 + cnt);
		m = cnt; //m代表有多少条线 
		cnt = unique(fy + 1, fy + 1 + cnt) - fy - 1; //代表离散化后y点的数量 
		ll ans = 0;
		for (int z = -500; z <= 500; z++) {
			build(1, 1, cnt - 1);
			int lastx = 0;
			for (int i = 1; i <= m; i++) {
				if (line[i].z1 <= z && line[i].z2 > z) {
					ans += (ll)tr[1].len3 * (line[i].x - lastx), lastx = line[i].x;
					update(1, 1, cnt - 1, find(line[i].s), find(line[i].e) - 1, line[i].st);
				} 
			}
 		}
 		printf("Case %d: %lld\n", ci, ans);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值