题目点这里
贴个链接,链接在这里~,扫描线启蒙;
------------------------------------------------------------------------------------------------------------------------------------------------------
题目大意:
有多组测试数据;
给出n个矩形的左下和右上的点的横纵坐标(%lf);
求这n个矩形的总面积不能重复计算;
------------------------------------------------------------------------------------------------------------------------------------------------------
思路:
既然给的是浮点型(%lf)就先会想到离散;
求并面积那么就会想到用扫描线~~~~~~~~~;
扫描线可以从上下方向也可以左右,我比较倾向于上下啦;
因为自下往上扫,所以记录平行于x轴的矩形的边的各种信息(左右端点的坐标,出入(出为-1入为1),所对应的
y轴的坐标),以离散化后的x轴构建线段树;
只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的y定位 - 上一线
段的y定位)*(该区间的大小)
------------------------------------------------------------------------------------------------------------------------------------------------------
代码:
建树做注意事项;
扫描线的3个作用之一:求并面积;
熟练掌握链接里面的第二种方法!
------------------------------------------------------------------------------------------------------------------------------------------------------
这是一道很裸的扫描线求并面积的题,欢迎去刷~
------------------------------------------------------------------------------------------------------------------------------------------------------
题目大意:
有多组测试数据;
给出n个矩形的左下和右上的点的横纵坐标(%lf);
求这n个矩形的总面积不能重复计算;
------------------------------------------------------------------------------------------------------------------------------------------------------
思路:
既然给的是浮点型(%lf)就先会想到离散;
求并面积那么就会想到用扫描线~~~~~~~~~;
扫描线可以从上下方向也可以左右,我比较倾向于上下啦;
因为自下往上扫,所以记录平行于x轴的矩形的边的各种信息(左右端点的坐标,出入(出为-1入为1),所对应的
y轴的坐标),以离散化后的x轴构建线段树;
只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的y定位 - 上一线
段的y定位)*(该区间的大小)
------------------------------------------------------------------------------------------------------------------------------------------------------
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct node
{
int l,r,cover;
double left_x,right_x,temp_y;
}e[110*1000];
struct edge
{
double y,left_x,right_x;
int flag;
bool operator < (const edge &a)const{return y < a.y;}
}line[110<<1];
double x[110<<1];
int cas,n,cnt;
double x1,x2,y1,y2;
void build(int k,int l,int r)
{
e[k].l = l,e[k].r = r;
e[k].left_x = x[l],e[k].right_x = x[r];
e[k].cover = 0,e[k].temp_y = -1;
if(l+1 == r)return;
int mid = (l + r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid,r);
//注意这里不是mid+1我就栽在这里T_T,因为这样的话左儿子的右边无法与右儿子的左边计算
}
double query(int k,double y,double l,double r,int flag)
{
if(l >= e[k].right_x || r <= e[k].left_x)return 0;
if(e[k].l + 1 == e[k].r)
{
if(e[k].cover)
{
double ans = (y - e[k].temp_y)*(e[k].right_x - e[k].left_x);
e[k].temp_y = y;//定位这次扫描线的y坐标
e[k].cover += flag;
return ans;
}
else
{
e[k].temp_y = y;
e[k].cover += flag;
return 0;
}
}
return query(k<<1,y,l,r,flag)+query(k<<1|1,y,l,r,flag);
}
int main()
{
while(scanf("%d",&n)!=EOF && n)
{
cnt = 0;
for(int i = 1;i <= n;i++)//记录每条扫描线的各种信息
{
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
line[++cnt].left_x = x1;
line[cnt].right_x = x2;
line[cnt].y = y1;
line[cnt].flag = 1;
x[cnt] = x1;
line[++cnt].left_x = x1;
line[cnt].right_x = x2;
line[cnt].y = y2;
line[cnt].flag = -1;
x[cnt] = x2;
}
sort(x+1,x+cnt+1);
sort(line+1,line+cnt+1);//离散操作
build(1,1,cnt);//以离散后的x轴建立坐标
double ans = 0;
for(int i = 1;i <= cnt;i++)
ans += query(1,line[i].y,line[i].left_x,line[i].right_x,line[i].flag);//开始扫描
printf("Test case #%d\nTotal explored area: %.2f\n\n", ++cas, ans);
}
return 0;
}
刷题感悟:建树做注意事项;
扫描线的3个作用之一:求并面积;
熟练掌握链接里面的第二种方法!
------------------------------------------------------------------------------------------------------------------------------------------------------
这是一道很裸的扫描线求并面积的题,欢迎去刷~