HDU 3642 Get The Treasury(离散化+线段树:扫描线)
http://acm.hdu.edu.cn/showproblem.php?pid=3642
分析:
本题要求的是重叠3次及以上的立方体体积,由于Z轴范围很小,可以枚举Z轴,然后固定了Z轴之后,就是求二维矩形的面积交>=3次的总面积了.其实Z轴就算很大也可以求,只需要把Z轴离散化即可.
比如Z轴从小到大出现了1,10,100,1000共四个值.然后假设当前考虑Z==1时,那么只需要把那些包括了[1,10]区间的立方体加入到二维矩形球面积的线段树扫描线中即可.如何判断一个立方体包括了区间[1,10]呢? 只要该立方体的Z轴最小值<=1且Z轴最大值>1,那么它就必然包括了区间[1,10].想想是不是.
对于每个给定的Z轴区间,我们只要求出交>=3次以上的总面积res,然后用res*该Z轴区间长度,即可求出该区间的ans体积.由于X轴的范围也很大,所以X轴也需要离散化处理.
线段树需要维护的信息有:
cover:值为0,1,2,3,4… 表示当前节点控制的X轴区被覆盖的次数.
sum: 表示当前节点控制的X轴区域被覆盖次数>=3的总长度
len1: 表示当前节点控制的X轴区域被覆盖次数=1的总长度
len2: 示当前节点控制的X轴区域被覆盖次数=2的总长度
具体实现见代码.
AC代码:1468ms
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=2222; #define lson i*2,l,m #define rson i*2+1,m+1,r int cover[MAXN*4],sum[MAXN*4],len1[MAXN*4],len2[MAXN*4]; int X[MAXN],Z[MAXN]; int cnt_x,cnt_z; struct seg { int l,r,h,d; seg(){} seg(int a,int b,int c,int d):l(a),r(b),h(c),d(d){} bool operator < (const seg& b)const { return h<b.h; } }ss[MAXN]; struct point { int x,y,z; void read() { scanf("%d%d%d",&x,&y,&z); } }; struct cube { point a,b; }cubes[MAXN]; void PushUp(int i,int l,int r) { if(cover[i]>=3) { sum[i]=X[r+1]-X[l]; len1[i]=len2[i]=0; } else if(cover[i]==2) { sum[i]=sum[i*2]+sum[i*2+1]+len1[i*2]+len1[i*2+1]+len2[i*2]+len2[i*2+1]; len2[i]=X[r+1]-X[l]-sum[i]; len1[i]=0; } else if(cover[i]==1) { sum[i]=sum[i*2]+sum[i*2+1]+len2[i*2]+len2[i*2+1]; len2[i]=len1[i*2]+len1[i*2+1]; len1[i]=X[r+1]-X[l]-sum[i]-len2[i]; } else { sum[i]=sum[i*2]+sum[i*2+1]; len1[i]=len1[i*2]+len1[i*2+1]; len2[i]=len2[i*2]+len2[i*2+1]; } } void update(int ql,int qr,int v,int i,int l,int r) { if(ql<=l&&r<=qr) { cover[i]+=v; PushUp(i,l,r); return ; } int m=(l+r)>>1; if(ql<=m) update(ql,qr,v,lson); if(m<qr) update(ql,qr,v,rson); PushUp(i,l,r); } int main() { int T; scanf("%d",&T); for(int kase=1;kase<=T;kase++) { int n; cnt_x=cnt_z=0; scanf("%d",&n); for(int i=1;i<=n;i++) { cubes[i].a.read(); cubes[i].b.read(); X[cnt_x++]=cubes[i].a.x; X[cnt_x++]=cubes[i].b.x; Z[cnt_z++]=cubes[i].a.z; Z[cnt_z++]=cubes[i].b.z; } if(n<3) { printf("Case %d: 0\n",kase); continue; } sort(X,X+cnt_x); sort(Z,Z+cnt_z); cnt_x=unique(X,X+cnt_x)-X; cnt_z=unique(Z,Z+cnt_z)-Z; long long ans=0; for(int i=0;i<cnt_z-1;i++) { int cnt=0; long long res=0; for(int j=1;j<=n;j++) { if(cubes[j].a.z<=Z[i] && cubes[j].b.z>Z[i]) { ss[cnt++]=seg(cubes[j].a.x,cubes[j].b.x,cubes[j].a.y,1); ss[cnt++]=seg(cubes[j].a.x,cubes[j].b.x,cubes[j].b.y,-1); } } sort(ss,ss+cnt); memset(cover,0,sizeof(cover)); memset(sum,0,sizeof(sum)); memset(len1,0,sizeof(len1)); memset(len2,0,sizeof(len2)); for(int j=0;j<cnt-1;j++) { int ql=lower_bound(X,X+cnt_x,ss[j].l)-X; int qr=lower_bound(X,X+cnt_x,ss[j].r)-X-1; update(ql,qr,ss[j].d,1,0,cnt_x-1); res +=(long long)sum[1]*(ss[j+1].h-ss[j].h); } ans += res*(Z[i+1]-Z[i]); } printf("Case %d: %I64d\n",kase,ans); } }