题意:给你n个矩形的左下角和右上角的坐标,现在问你这个复合矩形的总面积
思路:这就是线段树扫描线的裸题,扫描线就是在你的复合矩形上面加上一条虚拟的线,其中有两种一种是从左往右的扫描线,一种是从下到上的,这里我写的是从下到上的扫描线,先上图把
<来源见水印>
我们现在来讲一下,首先我们将横坐标离散,之后将离散后的坐标映射到线段树上,之后按照矩形和纵坐标从小到大排序(保证他是从最下往最上扫)当我们遇到下边的时候我们就将线段+1,表示这个时候我们加进来了一条边,遇到上边我们将对应的线段-1,这样之后就会像图中一样,会把矩形分割成为很多的小矩形,之后高度就是我们纵坐标的差,那么小矩形的长呢,我们就是用线段树维护小矩形的长。
上代码把:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#define lson l , m , rt<<1
#define rson m+1,r,rt<<1|1
const int maxnN = 220;
using namespace std;
struct Seg
{
double l,r,h;
int f;
Seg(){}
Seg(double a,double b,double c,double d):l(a),r(b),h(c),f(d){}
bool operator < (const Seg &cmp) const
{
return h<cmp.h;
}
}e[maxnN];
struct node
{
int cnt;
double len;
}sum[maxnN<<2];
double X[maxnN];
void pushdown(int l,int r,int rt)
{
if(sum[rt].cnt)
{
sum[rt].len = X[r+1] - X[l];
}
else if(l == r)
{
sum[rt].len = 0;
}
else
{
sum[rt].len = sum[rt<<1].len+sum[rt<<1|1].len;
}
}
void update(int L,int R,int l,int r, int rt,int val)
{
if(L<=l && R>=r)
{
sum[rt].cnt += val;
pushdown(l,r,rt);
return ;
}
int m = (l+r)>>1;
if(L<=m)
{
update(L,R,lson,val);
}
if(R>m)
{
update(L,R,rson,val);
}
pushdown(l,r,rt);
}
void print(int l,int r,int rt)
{
// cout<<"---"<<sum[rt].len<<endl;
if(l == r)
{
return ;
}
int m = (l+r)>>1;
print(lson);
print(rson);
}
int main()
{
int n;
double a,b,c,d;
int q = 1;
while(scanf("%d",&n)!=EOF)
{
memset(sum,0,sizeof(sum));
if(n == 0 )break;
int cnt = 0 ;
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+=(sum[1].len * (e[i+1].h - e[i].h));
// cout<<"sum = "<<sum[1].len<<endl;
print(0,n,1);
// puts("-------------------------------");
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",q++,ans);
}
return 0;
}