这次写了这个题目之后我发现之前对面积并的那个cal计数的意义还是理解还是有一点偏差:这个东西表示的是当前节点对应的线段整体覆盖的情况。为0时没有被全覆盖(注意不等于没有被覆盖),为1时被全覆盖了1次(意为min(l,r)==1,不代表不大于1),为k时表示min(l,r)==k。而且对应的只是一个节点对应的整个线段,跟只表示当前整段线段的状况,儿子是什么样不知道。。。
这个题也貌似有很多种方法,我参考了一位前辈的博客之后用了Len1表示全覆盖次数≥1的长度,Len2表示全覆盖次数≥2的长度,当然全部都是针对当前节点。Len1的维护方法和面积并的方法完全一样。然后Len2维护的时候就是,如果cnt[o]大于等于2,那么说明当前节点被全覆盖了两次,直接Len2=Len1,如果为1,说明当前节点被全覆盖了一次,那么只需要加上子节点中被全覆盖了一次的Len1就可以了(这样相当于在双亲节点里覆盖了两次),如果是叶子节点,没有孩子,那就直接是0,如果cnt为0,那就只有孩子里面的被全覆盖了两次之和才能更新当前点了。
这里还有一个需要注意的是,如果cnt为0,那么要么说明,当前节点从来没有被计算过,要么说明只计算过子节点,所以不会出现错误。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<unordered_set>
#include<unordered_map>
#define eps 1e-6
//#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn=1e3+5;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
struct seg
{
double lt,rt,y;
int flag;
seg(){};
bool operator<(const struct seg &rhs)const {return y<rhs.y;}
}segs[maxn<<1];
int n,cntx,cnty;
double xs[maxn<<1],ys[maxn<<1];
int getX(double x){return lower_bound(xs+1,xs+1+cntx,x)-xs;}
int getY(double y){return lower_bound(ys+1,ys+1+cnty,y)-ys;}
double Len1[maxn<<4],Len2[maxn<<4];
int cnt[maxn<<4];
void maintain(int o,int l,int r)//[l,r)
{
if(cnt[o])
Len1[o]=xs[r]-xs[l];
else
Len1[o]=Len1[o<<1]+Len1[o<<1|1];
if(cnt[o]>1)
Len2[o]=Len1[o];
else if(cnt[o]==1&&l<r-1)
Len2[o]=Len1[o<<1]+Len1[o<<1|1];//the most important
else if(cnt[o]==1&&l==r-1)
Len2[o]=0.0;
else
Len2[o]=Len2[o<<1]+Len2[o<<1|1];
}
int pl,pr,v;
void update(int o,int l,int r)
{
if(l==r)return ;
if(pl<=l&&r<pr)
{
cnt[o]+=v;
}
else if(l!=r-1)
{
int mid=(l+r)>>1;
if(pl<mid)update(o<<1,l,mid);
if(mid<pr)update(o<<1|1,mid,r);
}
/*有没有return都一样
else
{
return ;
}
*/
maintain(o,l,r);
}
int main()
{
//freopen("1.txt","r",stdin);
//freopen("2.txt","w",stdout);
int T;
double x1,x2,y1,y2;
scanf("%d",&T);
while(T--)
{
memset(Len1,0,sizeof(Len1));
memset(Len2,0,sizeof(Len2));
memset(cnt,0,sizeof(cnt));
cntx=cnty=0;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
xs[++cntx]=x1,xs[++cntx]=x2;
ys[++cnty]=y1,ys[++cnty]=y2;
segs[2*i-1].lt=x1,segs[2*i-1].rt=x2,segs[2*i-1].y=y1,segs[2*i-1].flag=1;
segs[i<<1].lt=x1,segs[i<<1].rt=x2,segs[i<<1].y=y2,segs[i<<1].flag=-1;
}
sort(segs+1,segs+1+2*n);
sort(xs+1,xs+1+2*n);
sort(ys+1,ys+1+2*n);
cntx=cnty=1;
for (int i=2;i<=2*n;i++)
{
if(xs[i]!=xs[cntx])
xs[++cntx]=xs[i];
if(ys[i]!=ys[cnty])
ys[++cnty]=ys[i];
}
xs[cntx+1]=xs[cntx];
ys[cnty]=ys[cnty];
double ans=0.0;
for (int i=1;i<2*n;i++)
{
double ch=segs[i+1].y-segs[i].y;
pl=getX(segs[i].lt),pr=getX(segs[i].rt)+1,v=segs[i].flag;
update(1,1,cntx+1);
ans+=Len2[1]*(ch);
}
printf("%.2f\n",ans);
}
return 0;
}
