参考链接 : http://blog.csdn.net/zxy_snow/article/details/6870127
题意:给你n个立方体,求覆盖三次以上(包括三次)的区域的体积
思路:先将z坐标离散后,然后一层一层地开始扫描,计算该层中覆盖>=3次的面积,这个就同二维扫描一样,然后再用面积乘以这层的高度,
即得到该层覆盖>=3次的体积,所有层的体积加起来,即为所求。
对于每一层,只有当该层区域在扫描的线的z1,z2范围中,才将该线条插入。
其它操作就同POJ 1151 Atlantis 求矩形的面积并一样。
这里要注意的是,如果扫描的时候,是用单点更新,那么就会TLE。
后来看了网上别人的区间更新的代码,这才A了。
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #define lson rt<<1,L,mid #define rson rt<<1|1,mid,R /* AC 参考链接 http://blog.csdn.net/zxy_snow/article/details/6870127 题意:给你n个立方体,求覆盖三次以上(包括三次)的区域的体积 思路:先将z坐标离散后,然后一层一层地开始扫描,计算该层中覆盖>=3次的面积,这个就同二维扫描一样,然后再用面积乘以这层的高度, 即得到该层覆盖>=3次的体积,所有层的体积加起来,即为所求。 对于每一层,只有当该层区域在扫描的线的z1,z2范围中,才将该线条插入。 其它操作就同POJ 1151 Atlantis 求矩形的面积并一样。 这里要注意的是,如果扫描的时候,是用单点更新,那么就会TLE。 后来看了网上别人的区间更新代码,这才A了。 */ using namespace std; const int maxn=1005; int n; int xval[maxn*2],zval[maxn*2]; //存储x和z出现的所有值 int idx,idz; //xval和zval存储的数的个数 int hashx[maxn*2],hashz[maxn*2]; //用于离散化 int hx,hz; //x和z离散后的个数 long long ans; struct Line{ //l r:线条的横坐标左端点和右端点;y:纵坐标值 //z1 z2:线条所处的z坐标范围 int l,r,y,z1,z2; int tp; //标记,tp=1表示矩形的下边,tp=-1表示矩形的上边 bool operator<(const Line tmp)const{ return y<tmp.y; } }line[maxn*2]; struct Node{ int cnt; //该区间被覆盖的次数 /* once:该区间中被覆盖一次的线段长度 twice:该区间中被覆盖两次的线段长度 len:该区间中被覆盖>=三次的线段长度 */ long long once,twice,len; }tree[maxn<<3]; //二分搜索x坐标对应的离散值 int binarySearchx(int m){ int l=0,r=hx+1,mid; while(r-l>1){ mid=(l+r)>>1; if(hashx[mid]<=m) l=mid; else r=mid; } return l; } void build(int rt,int L,int R){ tree[rt].cnt=tree[rt].len=tree[rt].twice=tree[rt].once=0; if(L+1==R) return; int mid=(L+R)>>1; build(lson); build(rson); } /* 还是网上看了大牛们的代码,用区间查询,才AC 原本自己就直接单点更新,导致TLE。。。 */ void pushUp(int rt,int L,int R){ if(tree[rt].cnt>=3){ tree[rt].once=tree[rt].twice=0; tree[rt].len=hashx[R]-hashx[L]; } else if(tree[rt].cnt==2){ if(L+1==R){ tree[rt].once=tree[rt].len=0; tree[rt].twice=hashx[R]-hashx[L]; } else{ tree[rt].once=0; tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len+tree[rt<<1].twice+tree[rt<<1|1].twice +tree[rt<<1].once+tree[rt<<1|1].once; tree[rt].twice=hashx[R]-hashx[L]-tree[rt].len; } } else if(tree[rt].cnt==1){ if(L+1==R){ tree[rt].once=hashx[R]-hashx[L]; tree[rt].twice=tree[rt].len=0; } else{ tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len+tree[rt<<1].twice+tree[rt<<1|1].twice; tree[rt].twice=tree[rt<<1].once+tree[rt<<1|1].once; tree[rt].once=hashx[R]-hashx[L]-tree[rt].len-tree[rt].twice; } } else{ if(L+1==R){ tree[rt].len=tree[rt].once=tree[rt].twice=0; } else{ tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len; tree[rt].twice=tree[rt<<1].twice+tree[rt<<1|1].twice; tree[rt].once=tree[rt<<1].once+tree[rt<<1|1].once; } } } void update(int rt,int L,int R,int l,int r,int c){ if(l<=L&&R<=r){ tree[rt].cnt+=c; pushUp(rt,L,R); return; } int mid=(L+R)>>1; if(r<=mid) update(lson,l,r,c); else if(l>=mid) update(rson,l,r,c); else{ update(lson,l,mid,c); update(rson,mid,r,c); } pushUp(rt,L,R); } int main() { int t; int x1,y1,z1,x2,y2,z2; scanf("%d",&t); for(int q=1;q<=t;q++){ scanf("%d",&n); idx=idz=0; for(int i=1;i<=n;i++){ scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2); line[2*i-1].l=x1;line[2*i-1].r=x2;line[2*i-1].y=y1;line[2*i-1].z1=z1;line[2*i-1].z2=z2;line[2*i-1].tp=1; line[2*i].l=x1;line[2*i].r=x2;line[2*i].y=y2;line[2*i].z1=z1;line[2*i].z2=z2;line[2*i].tp=-1; xval[++idx]=x1; xval[++idx]=x2; zval[++idz]=z1; zval[++idz]=z2; } n=n*2; sort(line+1,line+n+1); sort(xval+1,xval+idx+1); sort(zval+1,zval+idz+1); hx=hz=0; //将x坐标值离散化 hashx[++hx]=xval[1]; for(int i=2;i<=idx;i++){ if(xval[i]!=xval[i-1]) hashx[++hx]=xval[i]; } //将y坐标值离散化 hashz[++hz]=zval[1]; for(int i=2;i<=idz;i++){ if(zval[i]!=zval[i-1]) hashz[++hz]=zval[i]; } ans=0; int minz,maxz; int a,b; //一层一层地扫描 for(int i=1;i<hz;i++){ //minz和maxz表示该层所处的范围 minz=hashz[i]; maxz=hashz[i+1]; build(1,1,hx); long long s=0; //该层被覆盖>=3的面积 int last=0; //记录上一次扫描线的编号 for(int j=1;j<=n;j++){ if(line[j].z1<=minz && maxz<=line[j].z2){ s+=tree[1].len*(line[j].y-line[last].y); last=j; a=binarySearchx(line[j].l); b=binarySearchx(line[j].r); update(1,1,hx,a,b,line[j].tp); } } ans+=s*(maxz-minz); } printf("Case %d: %I64d\n",q,ans); } return 0; }