题意: 给你n个矩形的左上角坐标和右下角坐标问你复合矩形中覆盖过至少两次的区域的面积.
思路:还是扫描线,不过线段树中多存了一个变量,ss表示的是覆盖过至少两次的面积,他是怎么算出来的呢?
首先我们的线段树里有一个cnt变量如果他不等于0就表示他的区间被完全覆盖,那么当他的cnt>1就表示他被完全覆盖了至少两次以上那么我们就可以合并ss的长度,如果等于1呢?就表示他的整个区间被覆盖了一次,那么我们找他的儿子区间的覆盖的区间相加就是两次的了,那如果等于0呢,就表示他没有被完全覆盖,那么就加上他的儿子区间上的覆盖两次以上的区间就好了,代码上面有上代码把:
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <iostream>
#define lson l , m, rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 2000+10;
struct Seg
{
double l,r,h;
int f;
Seg(){}
Seg(double a,double b,double c,int d):l(a),r(b),h(c),f(d){}
bool operator < (const Seg &cmp) const
{
return h < cmp.h;
}
}e[maxn];
struct node
{
double len; //len 区间的总长度
double ss; // ss表示的是覆盖区间超过两次的长度
int cnt; // 覆盖的次数
}edg[maxn<<2];
double X[maxn];
void pushdown(int l,int r,int rt)
{
if(edg[rt].cnt) edg[rt].len = X[r+1] - X[l];//如果完全覆盖就加上
else if(l == r) edg[rt].len = 0;
else edg[rt].len = edg[rt<<1].len + edg[rt<<1|1].len;
if(edg[rt].cnt > 1) edg[rt].ss = X[r+1] - X[l];//表示的是区间完全被覆盖了两次,加上整个长度
else if(l == r) edg[rt].ss = 0;
else if(edg[rt].cnt == 1) edg[rt].ss = edg[rt<<1].len + edg[rt<<1|1].len;//如果等于1表示他被完全覆盖一次,那么我们加上他的儿子区间就好了
else edg[rt].ss = edg[rt<<1].ss + edg[rt<<1|1].ss;//
}
void update(int L,int R,int l,int r,int rt,int val)
{
if(l>=L && R>=r)
{
edg[rt].cnt += val;
pushdown(l,r,rt);
return ;
}
int m = (r+l)>>1;
if(m>=L) update(L,R,lson,val);
if(R>m) update(L,R,rson,val);
pushdown(l,r,rt);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
memset(edg,0,sizeof(edg));
int cnt = 0 ;
double a,b,c,d;
scanf("%d",&n);
for(int i = 0 ; i < n ; i++)
{
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);//
X[cnt] = a;
e[cnt++] = Seg(a,c,b,1);
X[cnt] = c;
e[cnt++] = Seg(a,c,d,-1);
}
sort(X,X+cnt);
sort(e,e+cnt);
int m = unique(X,X+cnt) - X;
double ans = 0;
for(int i = 0 ; i < cnt ; i ++)
{
int l = lower_bound(X,X+m,e[i].l) - X;
int r = lower_bound(X,X+m,e[i].r) - X - 1;
update(l,r,0,m,1,e[i].f);
ans+=edg[1].ss*(e[i+1].h - e[i].h);
// cout<<edg[1].ss <<endl;
}
printf("%.2lf\n",ans);
}
}