bzoj 3225: [Sdoi2008] 立方体覆盖 题解
【原题】
3225: [Sdoi2008]立方体覆盖
Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 51 Solved: 36
[Submit][Status]
Description
A君按纵坐标建立线段树后按横坐标扫描计算。轻易AC了这道题,时间复杂度为O(NlogN)。
Input
Output
Sample Input
0 0 0 3
1 –1 0 1
19 3 5 6
Sample Output
HINT
对于 100% 的数据。1≤N≤100
对于 100% 的数据,-1000≤x, y, z≤1000。1≤r≤200
【做法1】n=100?暴力能过吗?暴力离散、统计。。极限效率大概是:200^3*100。并且去重能够提高一点效率。
【代码1】
#include<cstdio> #include<algorithm> #define N 105 #define M 210 using namespace std; int n,X,Y,Z,R,hx,hy,hz,tx,ty,tz,i,j,k,p,flag,ans; int x1[N],x2[N],y1[N],y2[N],z1[N],z2[N],xx[M],yy[M],zz[M],x[M],y[M],z[M]; int main() { scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%d%d%d%d",&X,&Y,&Z,&R); x1[i]=X-R;x2[i]=X+R; y1[i]=Y-R;y2[i]=Y+R; z1[i]=Z-R;z2[i]=Z+R; } for (i=1;i<=n;i++) { xx[++hx]=x1[i];xx[++hx]=x2[i]; yy[++hy]=y1[i];yy[++hy]=y2[i]; zz[++hz]=z1[i];zz[++hz]=z2[i]; } sort(xx+1,xx+hx+1);xx[0]=xx[1]-1; sort(yy+1,yy+hy+1);yy[0]=yy[1]-1; sort(zz+1,zz+hz+1);zz[0]=zz[1]-1; for (i=1;i<=hx;i++) if (xx[i]!=xx[i-1]) x[++tx]=xx[i]; for (i=1;i<=hy;i++) if (yy[i]!=yy[i-1]) y[++ty]=yy[i]; for (i=1;i<=hz;i++) if (zz[i]!=zz[i-1]) z[++tz]=zz[i]; for (i=1;i<tx;i++) for (j=1;j<ty;j++) for (k=1;k<tz;k++) { flag=1; for (p=1;p<=n&&flag;p++) if (x1[p]<=x[i]&&x[i+1]<=x2[p]&&y1[p]<=y[j]&&y[j+1]<=y2[p]&&z1[p]<=z[k]&&z[k+1]<=z2[p]) flag=0; if (!flag) ans+=(x[i+1]-x[i])*(y[j+1]-y[j])*(z[k+1]-z[k]); } printf("%d",ans); return 0; }
【分析2】那么我们就乖乖地写标算。显然。直接线段树套线段树有点虚啊。
于是我先枚举离散后的H,再次基础上建立满足条件的x和y。这样转化成了经典的NLOG(N)的矩形面积并了。
利用扫描线的思想。把每一条竖边取出并按x从左到右快排。然后扫描。假设一条边是始边,把线段树中的y1--y2加1。否则把y1--y2减1。然后对于每个不同的x,把线段树中覆盖层数大于1的个数*(x[i+1]-x[i])。
这个线段树的细节非常多。比方线段树建立是l~mid,mid~r。然后叶子节点是l~l+1。
【代码2】
#include<cstdio> #include<algorithm> #define N 105 #define A 1200 #define M 210 using namespace std; struct Tree{int l,r,sum,cover;}a[M*2*16]; struct arr { int x,l,r,p; friend bool operator < (const arr &a,const arr &b) { if (a.x!=b.x) return a.x<b.x; return !a.p&&b.p; } }E[M*2]; int n,X,Y,Z,r,hz,tz,L,R,i,j,k,opt,h,hy,ty,p,tot,flag,temp,H,W,ans; int x1[N],x2[N],y1[N],y2[N],z1[N],z2[N],zz[M],z[M],yy[M],y[M],pre[2405]; void build(int k,int l,int r) { a[k].l=l;a[k].r=r;a[k].sum=0;a[k].cover=0; if (l+1==r||l==r) return;int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid,r); } void Cover_Add(int k) { if (L<=a[k].l&&a[k].r<=R) { if (!opt) a[k].cover++,a[k].sum=y[a[k].r]-y[a[k].l]; else if (!(--a[k].cover)) a[k].sum=(a[k].l+1>=a[k].r)?0:a[k<<1].sum+a[(k<<1)+1].sum; return; } int mid=(a[k].l+a[k].r)/2; if (L<mid) Cover_Add(k<<1); if (R>mid) Cover_Add(k<<1|1); if (!a[k].cover) a[k].sum=a[k<<1].sum+a[k<<1|1].sum; } int main() { scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%d%d%d%d",&X,&Y,&Z,&r); x1[i]=X-r;x2[i]=X+r; y1[i]=Y-r;y2[i]=Y+r; z1[i]=Z-r;z2[i]=Z+r; } for (i=1;i<=n;i++) zz[++hz]=z1[i],zz[++hz]=z2[i]; sort(zz+1,zz+hz+1);zz[0]=zz[1]-1; for (i=1;i<=hz;i++) if (zz[i]!=zz[i-1]) z[++tz]=zz[i]; for (k=1;k<tz;k++) { H=z[k+1]-z[k];h=hy=ty=0;temp=tot=0; for (i=1;i<=n;i++) if (z1[i]<=z[k]&&z[k+1]<=z2[i]) { E[++h]=(arr){x1[i],y1[i],y2[i],0}; E[++h]=(arr){x2[i],y1[i],y2[i],1}; yy[++hy]=y1[i];yy[++hy]=y2[i]; } sort(yy+1,yy+hy+1);yy[0]=yy[1]-1; for (i=1;i<=hy;i++) if (yy[i]!=yy[i-1]) y[++ty]=yy[i],pre[yy[i]+A]=++tot; if (!ty) continue; sort(E+1,E+h+1);build(1,1,ty); for (i=1;i<h;i++) { W=E[i+1].x-E[i].x; L=pre[E[i].l+A];R=pre[E[i].r+A];opt=E[i].p; Cover_Add(1); if (E[i].x!=E[i+1].x||i+1==h) temp+=a[1].sum*W; } ans+=temp*H; } printf("%d",ans); return 0; }