#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
/*开一个存线段区间的结构体
记录下该竖着的线段区间的横坐标,
和两个纵坐标。
并且按照横坐标排序,就能完美还原出
图中从左到右那一根根竖线了
*/
struct Segment
{
double x,y1,y2;
int k; //k是属于矩形的编号
bool operator<(const Segment &t)const{
return x<t.x;
}
}seg[N*2]; //因为一个矩形两个竖线,所以要开2*N
struct Node
{
int l,r;
int cnt; //区间被覆盖的次数
double len; //总长度
}tr[8*N];
vector<double> ys; //离散化数组
int find(double y) //二分查找离散化后的值
{
return lower_bound(ys.begin(),ys.end(),y)-ys.begin();
}
void pushup(int u)
{
if(tr[u].cnt) //如果cnt是大于0的,那么长度可以直接算了
{
tr[u].len=ys[tr[u].r+1]-ys[tr[u].l];
}
else if(tr[u].l!=tr[u].r) //如果cnt=0,就判断两个儿子是否为叶节点
{
tr[u].len=tr[u<<1].len+tr[u<<1|1].len;
}
else tr[u].len=0; //如果是叶节点
}
void modify(int u,int l,int r,int k)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].cnt+=k;
pushup(u);
}
else
{
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid)
{
modify(u<<1,l,r,k);
}
if(r>mid)
{
modify(u<<1|1,l,r,k);
}
pushup(u);
}
}
void build(int u,int l,int r)
{
tr[u]={l,r,0,0};
if(l!=r)
{
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
}
int main()
{
int T=1;
while(scanf("%d",&n)!=EOF&&n)
{
ys.clear(); //离散化的数组清空
for(int i=0,j=0;i<n;i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
seg[j++]={x1,y1,y2,1};
seg[j++]={x2,y1,y2,-1};
ys.push_back(y1);
ys.push_back(y2);
}
sort(ys.begin(),ys.end());
ys.erase(unique(ys.begin(),ys.end()),ys.end());
//把所有线段排个序
sort(seg,seg+n*2);
//下面要写一个二分,辅助查找离散化后的值
//由于是区间个数,所以在点数ys.size()-1的情况下还要-1
build(1,0,ys.size()-2);
double res=0;
for(int i=0;i<n*2;i++)
{
if(i>0) res+=tr[1].len*(seg[i].x-seg[i-1].x);
modify(1,find(seg[i].y1),find(seg[i].y2)-1,seg[i].k);
}
printf("Test case #%d\n",T++);
printf("Total explored area: %.2lf\n\n",res);
}
}