Atlantis
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11332 Accepted Submission(s): 4817
The input file is terminated by a line containing a single 0. Don’t process it.
Output a blank line after each test case.
2 10 10 20 20 15 15 25 25.5 0
Test case #1 Total explored area: 180.00
题意:给出n个矩形,形式是左下点和右上点。求它们的面积并。
解题思路:扫描线算法
以下为转载内容,转载地址:http://www.cnblogs.com/fenshen371/p/3214092.html 代码为自己理解后手码
线段树扫描法的题,顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中,这根线很重要。方向的话,可以左右扫,也可以上下扫。方法是一样的,这里我用的是由下向上的扫描法。
如上图所示,坐标系内有两个矩形。位置分别由左下角和右上角顶点的坐标来给出。上下扫描法是对x轴建立线段树,矩形与y平行的两条边是没有用的,在这里直接去掉。如下图。
现想象有一条线从最下面的边开始依次向上扫描。线段树用来维护当前覆盖在x轴上的线段的总长度,初始时总长度为0。用ret来保存矩形面积总和,初始时为0。
由下往上扫描,扫描到矩形的底边时将它插入线段树,扫描到矩形的顶边时将底边从线段树中删除。而在代码中实现的方法就是,每条边都有一个flag变量,底边为1,顶边为-1。
用cover数组(通过线段树维护)来表示某x轴坐标区间内是否有边覆盖,初始时全部为0。插入或删除操作直接让cover[] += flag。当cover[] > 0 时,该区间一定有边覆盖。
开始扫描到第一条线,将它压入线段树,此时覆盖在x轴上的线段的总长度L为10。计算一下它与下一条将被扫描到的边的距离S(即两条线段的纵坐标之差,该例子里此时为3)。
则 ret += L * S. (例子里增量为10*3=30)
结果如下图
橙色区域表示已经计算出的面积。
扫描到第二条边,将它压入线段树,计算出此时覆盖在x轴上的边的总长度。
例子里此时L=15。与下一条将被扫描到的边的距离S=2。 ret += 30。 如下图所示。
绿色区域为第二次面积的增量。
接下来扫描到了下方矩形的顶边,从线段树中删除该矩形的底边,并计算接下来面积的增量。如下图。
蓝色区域为面积的增量。
此时矩形覆盖的总面积已经计算完成。 可以看到,当共有n条底边和顶边时,只需要从下往上扫描n-1条边即可计算出总面积。
============================== 分割线 ========================================
此题因为横坐标包含浮点数,因此先离散化。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <stack>
#include <map>
#include <climits>
using namespace std;
#define LL long long
const int maxn=110;
struct LINE
{
double y,x_l,x_r;
int flag;
friend bool operator<(LINE a,LINE b)
{
return a.y<b.y;
}
}line[2*maxn];
struct TREE
{
double x_l,x_r;
double y;
int cover;
bool flag;
}tree[1000*maxn];
int n;
double x1,y1,x2,y2;
int sum;
double x[2*maxn];
void build(int k,int l,int r)
{
tree[k].y=-1;
tree[k].cover=0;
tree[k].x_l=x[l];
tree[k].x_r=x[r];
tree[k].flag=false;
if(l+1==r)
{
tree[k].flag=true;
return;
}
int mid=(l+r)>>1;
build(2*k,l,mid);
build(2*k+1,mid,r);
}
double query(int k,double y,double l,double r,int flag)
{
if(r<=tree[k].x_l||l>=tree[k].x_r)
return 0;
if(tree[k].flag)
{
if(tree[k].cover)
{
double temp_y=tree[k].y;
double ans=(y-temp_y)*(tree[k].x_r-tree[k].x_l);
tree[k].y=y;
tree[k].cover+=flag;
return ans;
}
else
{
tree[k].cover+=flag;
tree[k].y=y;
return 0;
}
}
double ans1,ans2;
ans1=query(2*k,y,l,r,flag);
ans2=query(2*k+1,y,l,r,flag);
return ans1+ans2;
}
int main()
{
int cas=0;
while(~scanf("%d",&n)&&n)
{
sum=1;
for(int i=1;i<=n;i++)
{
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
x[sum]=x1;
line[sum].y=y1;
line[sum].x_l=x1;
line[sum].x_r=x2;
line[sum].flag=1;
sum++;
x[sum]=x2;
line[sum].y=y2;
line[sum].x_l=x1;
line[sum].x_r=x2;
line[sum].flag=-1;
sum++;
}
sort(x+1,x+sum);
sort(line+1,line+sum);
build(1,1,sum-1);
double ans=0;
for(int i=1;i<sum;i++)
ans+=query(1,line[i].y,line[i].x_l,line[i].x_r,line[i].flag);
printf("Test case #%d\nTotal explored area: %.2f\n\n", ++cas,ans);
}
return 0;
}