题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642
题目大意:给出n个长方体对角的两个坐标 求长方体三个重叠的体积 (求体积交)
思路:建议按顺序先做下
hdu1542 求平面n个矩形的面积并 http://blog.csdn.net/qq_36782366/article/details/75209119
hdu1255 求平面n个矩形的面积交 http://blog.csdn.net/qq_36782366/article/details/75216430
一:总体的思路
本题的主要思路是将x轴和z轴离散化,然后对于z轴每个扫描线,求当前高度下水平面重叠三次的面积,然后乘以高度即可。
二:变量的解释。
int x[maxn],z[maxn],n,cntx,cntz;
int sum[maxn<<2],once[maxn<<2],twice[maxn<<2];
int cover[maxn<<2];
struct seg{
int l,r,h;
int flag;
seg(){};
seg(int _l,int _r,int _h,int _flag):l(_l),r(_r),h(_h),flag(_flag){}
bool operator < (const seg &cmp)const {
if(h==cmp.h) return flag>cmp.flag;
return h<cmp.h;
}
}ss[maxn];
struct point { //一个坐标点
int x,y,z;
void get()
{
scanf("%d%d%d",&x,&y,&z);
}
};
struct pp{ //存储立方体的两个角的坐标
point a,b;
}cube[1111];
point结构体 存的是每个点的坐标
pp结构体 存的是一个长方体的两个点
seg结构体 用于求当前高度下水平面矩形的面积交
x数组和cntx z数组和cntz 分别是对x轴和y轴的离散化
sum[maxn<<2],once[maxn<<2],twice[maxn<<2]; 指的是重叠一层 重叠两层 重叠三层以上的长度
int cover[maxn<<2]; 记录当前区间被叠了几层 这边说明下标记cover不传递 他就指当前区间长度的边有几条
三:关于pushup函数的解释(重点)
void pushup(int rt,int l,int r)
{
if(cover[rt]==3)
{
sum[rt]=x[r+1]-x[l];
once[rt]=0;
twice[rt]=0;
return ;
}
if(cover[rt]==2)
{
sum[rt]=once[rt<<1]+once[rt<<1|1]+sum[rt<<1]+sum[rt<<1|1]+twice[rt<<1]+twice[rt<<1|1];
once[rt]=0;
twice[rt]=x[r+1]-x[l]-sum[rt];
return ;
}
if(cover[rt]==1)
{
sum[rt]=twice[rt<<1]+twice[rt<<1|1]+sum[rt<<1]+sum[rt<<1|1];
twice[rt]=once[rt<<1]+once[rt<<1|1];
once[rt]=x[r+1]-x[l]-sum[rt]-twice[rt];
return ;
}
if(cover[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];
return ;
}
}
对这个的理解是重中之重!!
如果cover【rt】等于3时,说明该区间被该区间长度的边覆盖了三层,所以对于sum(三层以上的长度)就是该区间的长度,因为已经覆盖三层了,所以once和twice的长度即为0
如果cover【rt】等于2时,说明该区间被该区间长度的边覆盖了两层,所以对于sum(三层以上的的长度)就是其子区间中覆盖一层和两层和三层以上的长度和,对于twice即等于总的该区间长度减去三层以上的长度,因为已经覆盖了至少两层,所以once一层的长度一定为0
如果cover【rt】等于1时,说明该区间被该区间长度的边覆盖了一层,所以对于sum(三层以上的的长度)就是其子区间中覆盖两层和三层以上的长度和,对于twice即等于其子区间中覆盖一层的长度和,once一层的长度为总的该区间长度减去三层以上的长度和两层的长度
如果cover【rt】等于0时,说明该区间没有被该区间长度的边覆盖,所以对于sum(三层以上的的长度)就是其子区间中覆盖三层以上的长度和,对于twice即等于其子区间中覆盖两层的长度和,once一层的长度即等于其子区间中覆盖一层的长度和
其他需要注意的是离散化的方法,巧妙的运用现有的函数 方便简洁!!!!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 lld;
const int maxn = 2222;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int x[maxn],z[maxn],n,cntx,cntz;
int sum[maxn<<2],once[maxn<<2],twice[maxn<<2];
int cover[maxn<<2];
struct seg{
int l,r,h;
int flag;
seg(){};
seg(int _l,int _r,int _h,int _flag):l(_l),r(_r),h(_h),flag(_flag){}
bool operator < (const seg &cmp)const {
if(h==cmp.h) return flag>cmp.flag;
return h<cmp.h;
}
}ss[maxn];
struct point { //一个坐标点
int x,y,z;
void get()
{
scanf("%d%d%d",&x,&y,&z);
}
};
struct pp{ //存储立方体的两个角的坐标
point a,b;
}cube[1111];
void pushup(int rt,int l,int r)
{
if(cover[rt]==3)
{
sum[rt]=x[r+1]-x[l];
once[rt]=0;
twice[rt]=0;
return ;
}
if(cover[rt]==2)
{
sum[rt]=once[rt<<1]+once[rt<<1|1]+sum[rt<<1]+sum[rt<<1|1]+twice[rt<<1]+twice[rt<<1|1];
once[rt]=0;
twice[rt]=x[r+1]-x[l]-sum[rt];
return ;
}
if(cover[rt]==1)
{
sum[rt]=twice[rt<<1]+twice[rt<<1|1]+sum[rt<<1]+sum[rt<<1|1];
twice[rt]=once[rt<<1]+once[rt<<1|1];
once[rt]=x[r+1]-x[l]-sum[rt]-twice[rt];
return ;
}
if(cover[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];
return ;
}
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
cover[rt]+=c;
pushup(rt,l,r);
return ;
}
int m=(l+r)>>1;
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
pushup(rt,l,r);
}
lld solve()
{
int i,j;
sort(x,x+cntx); //排序去重 离散化
sort(z,z+cntz);
cntx=unique(x,x+cntx)-x;
cntz=unique(z,z+cntz)-z;
lld ans=0;
for(i=0;i<cntz-1;i++)
{
int tot=0;
for(j=1;j<=n;j++)//求一个水平面的面积
{
if(cube[j].a.z<=z[i] && cube[j].b.z>z[i])
{
int x1=cube[j].a.x,x2=cube[j].b.x;
int y1=cube[j].a.y,y2=cube[j].b.y;
ss[tot++]=seg(x1,x2,y1,1);
ss[tot++]=seg(x1,x2,y2,-1);
}
}
memset(cover,0,sizeof(cover));
memset(sum,0,sizeof(sum));
memset(once,0,sizeof(0));
memset(twice,0,sizeof(twice));
sort(ss,ss+tot);
lld area=0;
int left=lower_bound(x,x+cntx,ss[0].l)-x;//在x离散化中的下标 这里需要学习lower_bound的使用 不用自己写二分查找了
int right=lower_bound(x,x+cntx,ss[0].r)-x-1;
update(left,right,ss[0].flag,0,cntx-1,1);//二维空间求面积
for(j=1;j<tot;j++)
{
area+=(lld)sum[1]*(ss[j].h-ss[j-1].h);
left=lower_bound(x,x+cntx,ss[j].l)-x;
right=lower_bound(x,x+cntx,ss[j].r)-x-1;
update(left,right,ss[j].flag,0,cntx-1,1);
}
ans+=area*(z[i+1]-z[i]);
}
return ans;
}
int main()
{
int t,ca=1,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
cntx=cntz=0;
for(i=1;i<=n;i++)
{
cube[i].a.get();
x[cntx++]=cube[i].a.x;//对x轴和z轴进行离散化
z[cntz++]=cube[i].a.z;
cube[i].b.get();
x[cntx++]=cube[i].b.x;
z[cntz++]=cube[i].b.z;
}
if(n<3)
{
printf("Case %d: 0\n",ca++);
continue;
}
lld ans=solve();
printf("Case %d: %I64d\n",ca++,ans);
}
return 0;
}