CF上遇到一题扫描线,二话不说立刻补。
该类题目计算坐标中边平行于x,y轴的矩形的覆盖面积。
这样可以通过离散化x坐标,然后建立区间,通过线段树管理。
然后每条扫描线更新区间覆盖和计算面积。
对于上面的矩形就有4条扫描线,有3个区间。
第一条扫描线覆盖1,2区间。
第二条扫描线覆盖2,3区间。
第三条扫描线是第一个矩阵的下边,所以取消1,2区间的覆盖,但因为区间2还有第二条扫描线仍然覆盖区间2,故总覆盖依然是2,3区间。
如何判断区间是否被覆盖,可以通过区别矩阵上下边来达成,上边cover值为1,下边cover值为-1,则被覆盖的区间覆盖值不为0。
代码如下:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
#define lson(i) i*2
#define rson(i) i*2+1
const int maxn=4222;
struct Node
{
double x1,x2,y;
int c;
Node(){}
Node(double x1,double x2,double y,int c):x1(x1),x2(x2),y(y),c(c){}
bool operator<(const Node& b)const
{
return y>b.y;
}
}line[maxn];
double x[maxn];
int flag[maxn];
double sum[maxn];
int ql,qr;
int bfind(int l,int r,double v)
{
int m;
while(l<r)
{
m=l+(r-l)/2;
if(x[m]<v)l=m+1;
else r=m;
}
return l;
}
void pushup(int i,int l,int r)
{
if(flag[i])sum[i]=x[r]-x[l-1];
else if(l==r)sum[i]=0;
else sum[i]=sum[lson(i)]+sum[rson(i)];
}
void update(int i,int l,int r,int c)
{
if(ql<=l&&r<=qr)
{
flag[i]+=c;
pushup(i,l,r);
}
else
{
int m=l+(r-l)/2;
if(ql<=m)update(lson(i),l,m,c);
if(m<qr)update(rson(i),m+1,r,c);
pushup(i,l,r);
}
}
int main()
{
//freopen("in.txt","r",stdin);
int n,t=0;
double x1,x2,y1,y2;
int cot;
while(scanf("%d",&n)==1&&n)
{
memset(sum,0,sizeof(sum));
memset(flag,0,sizeof(flag));
cot=0;
for(int i=0;i<n;i++)
{
//cin>>x1>>y1>>x2>>y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
line[cot]=Node(x1,x2,y1,1);
x[cot++]=x1;
line[cot]=Node(x1,x2,y2,-1);
x[cot++]=x2;
}
sort(x,x+cot);
sort(line,line+cot);
int k=0;
double ans=0;
for(int i=1;i<cot;i++)
if(x[i]!=x[i-1])x[++k]=x[i];
for(int i=0;i<cot-1;i++)
{
ql=bfind(0,k,line[i].x1)+1;
qr=bfind(0,k,line[i].x2);
update(1,1,k,line[i].c);
ans+=sum[1]*(line[i].y-line[i+1].y);
}
printf("Test case #%d\n",++t);
printf("Total explored area: %.2lf\n\n",ans);
}
return 0;
}