#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int N=101010;
struct Node
{
double x,yl,yh;
int w;
bool operator<(Node t)const
{
return x<t.x;
}
}edge[N];
struct
{
int l,r,cover;
}tr[N];
double ys[N];
void build(int u,int l,int r)
{
int mid=l+r>>1;
tr[u].l=l,tr[u].r=r;
tr[u].cover=0;
if (r-l>1)
{
build(u<<1,l,mid);
build(u<<1|1,mid,r);
}
}
void modify(int u,int l,int r,int val)
{
int mid=tr[u].l+tr[u].r>>1;
if(tr[u].l==l&&tr[u].r==r)
{
tr[u].cover+=val;
}
else if(tr[u].r-tr[u].l>1)
{
if (l>=mid)
modify(u<<1|1,l,r,val);
else if(r<=mid)
modify(u<<1,l,r,val);
else
{
modify(u<<1,l,mid,val);
modify(u<<1|1,mid,r,val);
}
}
}
void query(int root,double &ans)
{
//如果被覆盖次数大于1
if (tr[root].cover>1)
ans+=ys[tr[root].r]-ys[tr[root].l];
//上式不满足时,可能往下的子区间满足,就往下递归
//如果不是叶节点
else if(tr[root].r-tr[root].l>1)
{
tr[root<<1].cover+=tr[root].cover;
tr[root<<1|1].cover+=tr[root].cover;
tr[root].cover=0;
query(root<<1,ans);
query(root<<1|1,ans);
}
}
int main()
{
int T,N;
double x1,x2,y1,y2,ans,res;
scanf("%d",&T);
while(T--)
{
res=0;
map<double,int>mp;
scanf("%d",&N);
for (int i=1,j=1;i<=N;++i,j+=2)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
//入边
edge[j].x=x1,edge[j].yl=y1,edge[j].yh=y2;
edge[j].w=1;
//出边
edge[j+1].x=x2,edge[j+1].yl=y1,edge[j+1].yh=y2;
edge[j+1].w=-1;
//扫描线
ys[j]=y1,ys[j+1]=y2;
}
//按x排序
sort(edge+1,edge+1+2*N);
//y离散化
sort(ys+1,ys+1+2*N);
int cnt=unique(ys+1,ys+1+2*N)-(ys+1);
build(1,1,cnt);
//离散化
//映射之后的编号 ,查询的实话再映射到ys中去
for (int i=1;i<=cnt;++i)
mp[ys[i]]=i;
for (int i=1;i<2*N;++i)
{
ans=0;
//插进去
modify(1,mp[edge[i].yl],mp[edge[i].yh],edge[i].w);
query(1,ans);
res+=ans*(edge[i+1].x-edge[i].x);
}
printf("%.2lf\n",res);
}
return 0;
}