题目大意
给出一个L*W*H的空间,里面有N个长方体,求剩余空间里的最大立方体的棱长。
二维解法
其实可以去看一下另一道题叫纪念碑(JZOJ4238)
二分答案len,把所有矩形的右上边界延长len,把原框的左下边长延长len。
显然,如果某次延长以后仍有空隙,那么把边界还原后一定有空间为len*len的正方形。
既然还有空隙,那么仍可以继续延长,直到刚好没有空隙是就是答案。
至于怎么去找空隙,可以把矩形的左右边界求出来,左边+1右边-1,扫描线+线段树维护。
如果某次线段树中的最小值为0,就说明有空隙。
三维解法
其实只要把线段树改成线段树套线段树,维护一个面就行了。
然后矩形扩张时要三个面都扩张。
树套树的实现
鉴于这题比较特殊(维护一个面),所以可以直接多加一维来维护面。
每次如果长大于宽,就把长折半,否则把宽折半。
显然这样做每个面都是固定的。
最后到了目标面以内就直接修改。
code
#include <iostream>
#include <cstdio>
#include <cstring>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define Max_Len 2001
using namespace std;
int X1[Max_Len];
int Y1[Max_Len];
int Z1[Max_Len];
int X2[Max_Len];
int Y2[Max_Len];
int Z2[Max_Len];
int x1[Max_Len];
int y1[Max_Len];
int x2[Max_Len];
int y2[Max_Len];
int z[Max_Len];
int sz[Max_Len];
int tr[8000000][2];
int T,N,L,W,H,i,j,k,l,r,mid,N2,tttt;
void swap(int &a,int &b)
{
int c=a;
a=b;
b=c;
}
void qsort(int l,int r)
{
int i,j,k,mid;
i=l;
j=r;
mid=z[(l+r)/2];
while (i<=j)
{
while (z[i]<mid) i++;
while (z[j]>mid) j--;
if (i<=j)
{
swap(x1[i],x1[j]);
swap(y1[i],y1[j]);
swap(x2[i],x2[j]);
swap(y2[i],y2[j]);
swap(z[i],z[j]);
swap(sz[i],sz[j]);
i++;
j--;
}
}
if (l<j) qsort(l,j);
if (i<r) qsort(i,r);
return;
}
void down(int t)
{
if (tr[t][1])
{
tr[t][0]+=tr[t][1];
tr[t*2][1]+=tr[t][1];
tr[t*2+1][1]+=tr[t][1];
tr[t][1]=0;
}
}
void change(int t,int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2,int s)
{
int mid;
if ((X1<=x1) && (Y1<=y1) && (x2<=X2) && (y2<=Y2))
{
tr[t][1]+=s;
down(t);
return;
}
down(t*2);
down(t*2+1);
if ((x2-x1)>(y2-y1))//折半搜索
{
mid=(x1+x2)/2;
if ((X1<mid) && (x1<mid)) change(t<<1,x1,y1,mid,y2,X1,Y1,X2,Y2,s);
if ((mid<X2) && (mid<x2)) change((t<<1)+1,mid,y1,x2,y2,X1,Y1,X2,Y2,s);
}
else
{
mid=(y1+y2)/2;
if ((Y1<mid) && (y1<mid)) change(t<<1,x1,y1,x2,mid,X1,Y1,X2,Y2,s);
if ((mid<Y2) && (mid<y2)) change((t<<1)+1,x1,mid,x2,y2,X1,Y1,X2,Y2,s);
}
tr[t][0]=min(tr[t*2][0],tr[t*2+1][0]);
}
bool pd(int t)
{
int i,j;
memset(tr,0,sizeof(tr));
if (t)//把初始面扩张
{
change(1,0,0,L,W,0,0,L,t,1);
change(1,0,0,L,W,0,0,t,W,1);
}
j=1;
fo(i,t,H-1)//依次扫描
{
while ((j<=N2) && (z[j]<=i))
{
change(1,0,0,L,W,x1[j],y1[j],x2[j],y2[j],sz[j]);
j++;
}
if (!tr[1][0])
return 1;
}
return 0;
}
int main()
{
scanf("%d",&T);
fo(tttt,1,T)
{
scanf("%d%d%d%d",&N,&L,&W,&H);N2=N*2;
fo(i,1,N)
scanf("%d%d%d%d%d%d",&X1[i],&Y1[i],&Z1[i],&X2[i],&Y2[i],&Z2[i]);
l=0;
r=min(min(L,W),H);
while (l<r)
{
mid=(l+r)/2;
fo(i,1,N)//求每个面
{
x1[i*2-1]=X1[i];
y1[i*2-1]=Y1[i];
x2[i*2-1]=X2[i]+mid;
y2[i*2-1]=Y2[i]+mid;
z[i*2-1]=Z1[i];
sz[i*2-1]=1;
x1[i*2]=X1[i];
y1[i*2]=Y1[i];
x2[i*2]=X2[i]+mid;
y2[i*2]=Y2[i]+mid;
z[i*2]=Z2[i]+mid;
sz[i*2]=-1;
}
qsort(1,N2);
if (pd(mid))
l=mid+1;
else
r=mid;
}
printf("Case %d: %d\n",tttt,l);
}
return 0;
}