HDU 3642 - Get The Treasury - [加强版扫描线+线段树]
Posted dilthey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 3642 - Get The Treasury - [加强版扫描线+线段树]相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Jack can’t get the total volume of the treasury because these regions don’t always contain treasury. Through years of experience, he discovers that if a region is detected that may have treasury at more than two different spots, the region really exist treasure. And now Jack only wants to know the minimum volume of the treasury.
Now Jack entrusts the problem to you.
Each test case is given in some lines. In the first line there is an integer n (1 ≤ n ≤ 1000), the number of spots on the surface of the earth that he had detected. Then n lines follow, every line contains six integers x1, y1, z1, x2, y2 and z2, separated by a space. The absolute value of x and y coordinates of the vertices is no more than 106, and that of z coordinate is no more than 500.
题意:
给定一些长方体,求这些长方体相交至少3次的体积。
题解:
z坐标的范围 [-500, 500],比较小,所以可以枚举 z平面,用类似于扫描线扫描二维图形的方式,用扫描面扫描整个三维图形,而这些扫描面,就是所有长方体的上下平面,
那么,每个我们扫描得到的截面,就可以按照HDU1542里那样的普通的二维扫描线+线段树来做,求出这样一个截面上,重叠三次及以上的面积有多大,
同时,不难想到,若我们把长方体竖直的四个侧面,看成“下闭上开”(下沿取得到,上沿取不到)的话,当我们枚举到某一个平面 $z_i$ 时,该平面截得的截面,在区间 $left[ {z_i ,z_{i + 1} } ight)$ 都是不会变动的,这个和普通的二维扫描线+线段树的道理是一样的。
故,枚举到某一个平面 $z_i$ 时,该平面截得的截面积,乘上高度 ${z_{i + 1} - z_i }$ 之后,就是整个“3+次重叠体”在三维区间 $left[ {z_i ,z_{i + 1} } ight)$ 内的体积。
AC代码:
#include<bits/stdc++.h> typedef long long ll; using namespace std; const int maxn=1010; const int maxz=510; int n; vector<int> x; inline int getidx(int val){return lower_bound(x.begin(),x.end(),val)-x.begin();} vector<int> z; int tot; struct Segment { int x1,x2,y; int z1,z2; int flag; bool operator <(const Segment &oth)const{ return y<oth.y; } }segment[2*maxn],tmp[2*maxn]; /********************************* Segment Tree - st *********************************/ struct Node{ int l,r; int s; int once,twice,more; void show() { printf("l=%d r=%d s=%d once=%d twice=%d more=%d ",l,r,s,once,twice,more); } }node[8*maxn]; void pushup(int rt) { int ls=rt*2,rs=rt*2+1; if(node[rt].s>2) { node[rt].more=x[node[rt].r+1]-x[node[rt].l]; node[rt].once=node[rt].twice=0; } else if(node[rt].s==2) { if(node[rt].l==node[rt].r) { node[rt].more=0; node[rt].twice=x[node[rt].r+1]-x[node[rt].l]; node[rt].once=0; } else { node[rt].more=node[ls].once+node[ls].twice+node[ls].more+node[rs].once+node[rs].twice+node[rs].more; node[rt].twice=x[node[rt].r+1]-x[node[rt].l]-node[rt].more; node[rt].once=0; } } else if(node[rt].s==1) { if(node[rt].l==node[rt].r) { node[rt].more=0; node[rt].twice=0; node[rt].once=x[node[rt].r+1]-x[node[rt].l]; } else { node[rt].more=node[ls].twice+node[ls].more+node[rs].twice+node[rs].more; node[rt].twice=node[ls].once+node[rs].once; node[rt].once=x[node[rt].r+1]-x[node[rt].l]-node[rt].more-node[rt].twice; } } else { if(node[rt].l==node[rt].r) { node[rt].more=0; node[rt].twice=0; node[rt].once=0; } else { node[rt].more=node[ls].more+node[rs].more; node[rt].twice=node[ls].twice+node[rs].twice; node[rt].once=node[ls].once+node[rs].once; } } //printf("now pushup rt=%d ",rt); node[rt].show(); } void build(int rt,int l,int r) { if(l>r) return; node[rt].l=l; node[rt].r=r; node[rt].s=0; node[rt].once=node[rt].twice=node[rt].more=0; if(l==r) return; else { int mid=l+(r-l)/2; build(rt*2,l,mid); build(rt*2+1,mid+1,r); pushup(rt); } } void update(int root,int st,int ed,int val) { if(st>node[root].r || ed<node[root].l) return; if(st<=node[root].l && node[root].r<=ed) { node[root].s+=val; pushup(root); } else { update(root*2,st,ed,val); update(root*2+1,st,ed,val); pushup(root); } } /********************************* Segment Tree - st *********************************/ int main() { int T; scanf("%d",&T); for(int kase=1;kase<=T;kase++) { scanf("%d",&n); x.clear(); z.clear(); tot=0; for(int i=1;i<=n;i++) { int x1,y1,z1,x2,y2,z2; scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2); segment[tot].x1=x1; segment[tot].x2=x2; segment[tot].y=y1; segment[tot].z1=z1; segment[tot].z2=z2; segment[tot].flag=1; tot++; segment[tot].x1=x1; segment[tot].x2=x2; segment[tot].y=y2; segment[tot].z1=z1; segment[tot].z2=z2; segment[tot].flag=-1; tot++; x.push_back(x1); x.push_back(x2); z.push_back(z1); z.push_back(z2); } sort(x.begin(),x.end()); x.erase(unique(x.begin(),x.end()),x.end()); sort(z.begin(),z.end()); z.erase(unique(z.begin(),z.end()),z.end()); ll ans=0; for(int i=0;i<z.size()-1;i++) { //printf("now z=%d ",z[i]); int cnt=0; for(int j=0;j<tot;j++) if(segment[j].z1<=z[i] && segment[j].z2>z[i]) tmp[cnt++]=segment[j]; sort(tmp,tmp+cnt); build(1,0,x.size()); ll area=0; for(int j=0;j<cnt-1;j++) { int l=getidx(tmp[j].x1); int r=getidx(tmp[j].x2); //printf("now update y=%d [%d,%d](%d,%d) += %d ",tmp[j].y,x[l],x[r],l,r-1,tmp[j].flag); update(1,l,r-1,tmp[j].flag); area+=(ll)node[1].more*(tmp[j+1].y-tmp[j].y); } ans+=area*(z[i+1]-z[i]); } printf("Case %d: %I64d ",kase,ans); } }
以上是关于HDU 3642 - Get The Treasury - [加强版扫描线+线段树]的主要内容,如果未能解决你的问题,请参考以下文章
HDU3642 Get The Treasury —— 求矩形交体积 线段树 + 扫描线 + 离散化
HDU-3642 Get The Treasury(扫描线 + 离散化 + 线段树)
Get The Treasury HDU - 3642(体积扫描线)