HDU3642 Volume union in three-dimensional space

This question requires us to find the volume of a given n cuboid that overlaps more than three times in a three-dimensional space. And we only need to remove the z coordinate axis first and find the volume more than three times, that is, find the area overlapping three times on the two-dimensional plane and multiply it by the length of z existing on this area to get the volume.
So just Transform three-dimensional space problems into two-dimensional space processing

The key point is the writing of the pushup function in the case of three coverages:
sum1 represents coverage once, sum2 twice, sum3 three times or more.
1: If the cover tag is greater than 2, then sum3 is equal to the length of the current interval, and sum1 and sum2 are equal to 0 Because at this time there is no two cases of the following
2: the cover tag is covered exactly twice, and sum3 is equal to the length of the left and right subtrees covering three times plus the length of the left and right subtree covering 2 times plus the length of the left and right subtree covering once, because of these The length of the interval plus 2 may satisfy >=3, sum2 is equal to the length of the current interval minus sum3 (that is, the part greater than or equal to 3), sum1 is equal to 0
3: cover covers exactly once, then sum3 can only be equal to left and right The length of the interval covered by the tree twice and the length of the third time, sum2 is equal to the length of the left and right subtrees covering once, sum1 is equal to the length of the current interval minus the length of covering three or more times and twice
4: cover is equal to 0 All sums can only be used at this time Update by his left and right subtrees is equal to the sum of the corresponding left and right subtrees

void pushup(int rt,int l,int r)
{
    
    
	if(cover[rt] > 2){
    
    //覆盖三层及以上时 sum3直接加 sum2和sum1此时都是0 因为直接覆盖的三层
		sum3[rt] = x[r+1]-x[l];
		sum2[rt] = sum1[rt] = 0;
		return ;
	}
	else if(cover[rt] == 2){
    
    
		if(l == r){
    
    
			sum3[rt] = sum1[rt] = 0;
			sum2[rt] = x[r+1]-x[l];
		}
		else{
    
    //此时覆盖两层 那么三层的可由三的左右子树还有二的左右子树再加一的左右子树组成 因为这些加上2都可以达到3及以上
			sum3[rt]=sum3[rt<<1]+sum3[rt<<1|1]+sum2[rt<<1]+sum2[rt<<1|1]+sum1[rt<<1]+sum1[rt<<1|1];
			sum2[rt] = x[r+1]-x[l]-sum3[rt];//两层的长度 等于总的区间长度 减去三层的长度
			sum1[rt] = 0;
		}
	}
	else if(cover[rt] == 1){
    
    
		if(l == r){
    
    
			sum3[rt] = sum2[rt] = 0;
			sum1[rt] = x[r+1]-x[l];
			return ;
		}
		else{
    
    
			sum3[rt] = sum3[rt<<1]+sum3[rt<<1|1]+sum2[rt<<1]+sum2[rt<<1|1];
			sum2[rt] = sum1[rt<<1]+sum1[rt<<1|1];
			sum1[rt] = x[r+1]-x[l]-sum3[rt]-sum2[rt]; 
		}
	}
	else{
    
    
		if(l == r){
    
    
			sum3[rt] = sum2[rt] = sum1[rt] = 0;
			return ;
		}
		else{
    
    //相当于0 每个都只能通过 它自己的左右子树获得
			sum3[rt]=sum3[rt<<1]+sum3[rt<<1|1];
			sum2[rt]=sum2[rt<<1]+sum2[rt<<1|1];
			sum1[rt]=sum1[rt<<1]+sum1[rt<<1|1];
		}
	}
}

AC code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 1e5+7;
//三维空间的求体积并 只需要把z轴离散化后 挨个枚举z轴的区间 然后就变成了传统的二维空间的面积并
int sum1[MAXN],sum2[MAXN],sum3[MAXN];
int cover[MAXN];
int x[MAXN],z[MAXN];
int n;

struct Node
{
    
    
	int l,r,h,f;
}line[MAXN];

struct point
{
    
    
	int x,y,z;
};
struct node
{
    
    
	point a,b;
}cube[MAXN];
// 理解正确的多层面积的讨论方式(思想)

void init()
{
    
    
	memset(sum1,0,sizeof(sum1));
	memset(sum2,0,sizeof(sum2));
	memset(sum3,0,sizeof(sum3));
	memset(cover,0,sizeof(cover));
}

bool cmp(Node a,Node b){
    
    
	return a.h < b.h;
}

void pushup(int rt,int l,int r)
{
    
    
	if(cover[rt] > 2){
    
    //覆盖三层及以上时 sum3直接加 sum2和sum1此时都是0 因为直接覆盖的三层
		sum3[rt] = x[r+1]-x[l];
		sum2[rt] = sum1[rt] = 0;
		return ;
	}
	else if(cover[rt] == 2){
    
    
		if(l == r){
    
    
			sum3[rt] = sum1[rt] = 0;
			sum2[rt] = x[r+1]-x[l];
		}
		else{
    
    //此时覆盖两层 那么三层的可由三的左右子树还有二的左右子树再加一的左右子树组成 因为这些加上2都可以达到3及以上
			sum3[rt]=sum3[rt<<1]+sum3[rt<<1|1]+sum2[rt<<1]+sum2[rt<<1|1]+sum1[rt<<1]+sum1[rt<<1|1];
			sum2[rt] = x[r+1]-x[l]-sum3[rt];//两层的长度 等于总的区间长度 减去三层的长度
			sum1[rt] = 0;
		}
	}
	else if(cover[rt] == 1){
    
    
		if(l == r){
    
    
			sum3[rt] = sum2[rt] = 0;
			sum1[rt] = x[r+1]-x[l];
			return ;
		}
		else{
    
    
			sum3[rt] = sum3[rt<<1]+sum3[rt<<1|1]+sum2[rt<<1]+sum2[rt<<1|1];
			sum2[rt] = sum1[rt<<1]+sum1[rt<<1|1];
			sum1[rt] = x[r+1]-x[l]-sum3[rt]-sum2[rt]; 
		}
	}
	else{
    
    
		if(l == r){
    
    
			sum3[rt] = sum2[rt] = sum1[rt] = 0;
			return ;
		}
		else{
    
    //相当于0 每个都只能通过 它自己的左右子树获得
			sum3[rt]=sum3[rt<<1]+sum3[rt<<1|1];
			sum2[rt]=sum2[rt<<1]+sum2[rt<<1|1];
			sum1[rt]=sum1[rt<<1]+sum1[rt<<1|1];
		}
	}
}

void update(int rt,int l,int r,int ul,int ur,int x)
{
    
    
	if(l>=ul&&r<=ur){
    
    
		cover[rt]+=x;
		pushup(rt,l,r);
		return ;
	}
	int mid = (l+r)>>1;
	if(ul <= mid) update(rt<<1,l,mid,ul,ur,x);
	if(ur > mid) update(rt<<1|1,mid+1,r,ul,ur,x);
	pushup(rt,l,r);
}

int main()
{
    
    	
	int t,cas = 0;
	scanf("%d",&t);
	while(t--){
    
    
		ll ans = 0;
		int cntx = 0,cntz = 0;//需要分别对x和z离散化	
		scanf("%d",&n);
		for(int i = 1;i <= n;i ++){
    
    
			scanf("%d%d%d%d%d%d",&cube[i].a.x,&cube[i].a.y,&cube[i].a.z,&cube[i].b.x,&cube[i].b.y,&cube[i].b.z);
			x[++cntx] = cube[i].a.x;
			z[++cntz] = cube[i].a.z;
			x[++cntx] = cube[i].b.x;
			z[++cntz] = cube[i].b.z;
		}
		if(n < 3){
    
    
			printf("Case %d: 0\n",++cas);
			continue;
		}
		sort(x+1,x+1+cntx);
		sort(z+1,z+1+cntz);
		cntx = unique(x+1,x+1+cntx)-x-1;
		cntz = unique(z+1,z+1+cntz)-z-1;
// 枚举z坐标 每次把在这个范围内的矩形找出 每个循环中相当于做一次二维的扫描 就和前几道题一样了		
		for(int i = 1;i < cntz;i ++){
    
    
			int tot = 0;
			for(int k = 1;k <= n;k ++){
    
    
				if(cube[k].a.z<=z[i]&&cube[k].b.z>z[i]){
    
    
					int x1 = cube[k].a.x,x2 = cube[k].b.x;
					int y1 = cube[k].a.y,y2 = cube[k].b.y;
					line[++tot].l = x1,line[tot].r = x2,line[tot].h = y1,line[tot].f = 1;
					line[++tot].l = x1,line[tot].r = x2,line[tot].h = y2,line[tot].f = -1;
				}
			}
			init();// 这个就相当于建树 初始化了
			sort(line+1,line+1+tot,cmp);
			ll res = 0;
			for(int k = 1;k < tot;k ++){
    
    
				int l = lower_bound(x+1,x+1+cntx,line[k].l)-x;
				int r = lower_bound(x+1,x+1+cntx,line[k].r)-x-1;
				//printf("%d %d\n",l,r);
				update(1,1,cntx,l,r,line[k].f);
				res += (ll)sum3[1]*(line[k+1].h-line[k].h);
			}
			ans += res * (z[i+1]-z[i]);
		}
		printf("Case %d: %lld\n",++cas,ans);
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45672411/article/details/107244141