扫描线算法+线段树维护简介:

像这种求面积的并集的题目,就适合用扫描线算法解决,具体来说就是这样

类似这种给出点的矩形的对角的点的坐标,然后求出所有矩形面积的交集的问题,可以采用扫描线算法解决。图如下,我们要求红色部分的面积:

我们可以通过一条叫扫描线的东西解决问题。具体来说:

我们首先给自己一条线,这条可以我称之为标准线(棕色线表示)

从上往下(从下往上也行)我们把每个矩形用一个四元组表示了l,r,h,f  也就是说,把一个矩形用上下两条边表示,l,r分别是x1,x2,而h则是y坐标,f代表这条线是顶边还是低边。

这样就把信息存储下来。

需要注意的一点是,由于线段树维护区间的时候,会存在区间过大的清空,因此我们需要对x坐标进行去重排序,从而达到把点进行离散化,但是这里我们需要注意的是,我们这里维护区间,而线段树是从维护点,进而维护区间的,因此我们可以这样,把区间的左下标表示为区间,比如[0-3]区间,我们可以转化为点0,代表0-1,1代表1-2,2代表2-3。这样我们再找左端点的时候,我们之间用坐标代替,而右端点,则需要查找到下标后,减一即可。

维护总的区间的和,用高度差乘以区间和,就是面积,每次维护,求出面积,就是如上图所示的样子,从下往上不断求出面积。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
inline int L(int r){return r<<;};
inline int R(int r){return r<<|;};
inline int MID(int l,int r){return (l+r)>>;};
const int maxx = ;
struct segment{
double l,r,h;
int f;
}ss[maxx*];
struct node{
int l,r,cnt;
double len;
}tree[maxx<<];
double pos[maxx*];
int nums;
bool cmp(segment p,segment q)
{
return p.h<q.h;
}
void build(int root,int l,int r)
{
tree[root].l=l;
tree[root].r=r;
tree[root].cnt=;
tree[root].len=;
if (l==r)
return;
int mid = MID(tree[root].l,tree[root].r);
build(L(root),l,mid);
build(R(root),mid+,r);
}
void get_len(int root)
{
if (tree[root].cnt)//不是0 代表已经被整段覆盖
tree[root].len = pos[tree[root].r+] - pos[tree[root].l];
else if (tree[root].l == tree[root].r)//只是一个点
tree[root].len = ;
else
tree[root].len = tree[L(root)].len + tree[R(root)].len;
}
void update(int root,int l,int r,int val)
{
if (tree[root].l == l && tree[root].r == r)
{
tree[root].cnt += val;
get_len(root);
return;
}
int mid = (tree[root].l + tree[root].r)>>;
if (r<=mid)
update(L(root),l,r,val);
else if (l > mid)
update(R(root),l,r,val);
else {
update(L(root),l,mid,val);
update(R(root),mid+,r,val);
}
get_len(root);
}
int binary(double key,int low,int high)
{
// cout<<key<<endl;
int mid;
while(low<=high)
{
mid = MID(low,high);
if (pos[mid]==key)
return mid;
else if (key < pos[mid])
high = mid-;
else
low = mid+;
}
return -;
}
int main(){
int Case = ;
int n;
while(scanf("%d",&n)!=EOF && n)
{
nums=;
for (int i=;i<n;i++){
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
//记录下边
ss[nums].l = x1;
ss[nums].r = x2;
ss[nums].h = y1;
ss[nums].f = ;
//记录上边
ss[nums+].l = x1;
ss[nums+].r = x2;
ss[nums+].h = y2;
ss[nums+].f = -;
//记录横坐标
pos[nums] = x1;
pos[nums+] = x2;
nums+=;
}
sort(ss,ss+nums,cmp);
sort(pos,pos+nums);
int m = ;
for (int i=;i<nums;i++)//离散去重
if (pos[i]!=pos[i-])
pos[m++]=pos[i];
memset(tree,,sizeof(tree));
build(,,m-);//离散区间就是[0,m-1]
// for (int i=0;i<=m*4+2;i++){
// cout<<tree[i].l<<"-"<<tree[i].r<<endl;
// }
double ans = ;
for (int i=;i<nums-;i++)
{
int l = binary(ss[i].l,,m-);//二分找到s[i].l对应的离散化后的值
int r = binary(ss[i].r,,m-)-;//二分找到右端点但是由于需要把点转区间,因此减一
// cout<<ss[i].l<<"->"<<l<<" ";
// cout<<ss[i].r<<"->"<<r<<" ";
// cout<<ss[i+1].h<<"-"<<ss[i].h<<endl;
update(,l,r,ss[i].f);//更新区间
ans+=(ss[i+].h-ss[i].h)*tree[].len;
}
printf("Test case #%d\n", ++Case);
printf("Total explored area: %.2f\n\n", ans);
}
return ;
}

HDU - 1542 扫描线入门+线段树离散化的更多相关文章

  1. HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  2. 【42.49%】【hdu 1542】Atlantis(线段树扫描线简析)

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...

  3. 【HDU】5249-KPI(线段树+离散化)

    好久没写线段树都不知道怎么写了... 很easy的线段树二分问题 #include<cstdio> #include<set> #include<queue> #i ...

  4. HDU 1542"Atlantis"(线段树+扫描线求矩形面积并)

    传送门 •题意 给你 n 矩形,每个矩形给出你 $(x_1,y_1),(x_2,y_2)$ 分别表示这个矩形的左下角和右上角坐标: 让你求这 n 个矩形并的面积: 其中 $x \leq 10^{5} ...

  5. HDU - 1542 Atlantis(线段树求面积并)

    https://cn.vjudge.net/problem/HDU-1542 题意 求矩形的面积并 分析 点为浮点数,需要离散化处理. 给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1).(x ...

  6. hdu1542 矩形面积并(线段树+离散化+扫描线)

    题意: 给你n个矩形,输入每个矩形的左上角坐标和右下角坐标. 然后求矩形的总面积.(矩形可能相交). 题解: 前言: 先说说做这道题的感受: 刚看到这道题顿时就懵逼了,几何 烂的渣渣.后来从网上搜题解 ...

  7. 【POJ 2482】 Stars in Your Window(线段树+离散化+扫描线)

    [POJ 2482] Stars in Your Window(线段树+离散化+扫描线) Time Limit: 1000MS   Memory Limit: 65536K Total Submiss ...

  8. HDU 4288 Coder 【线段树+离线处理+离散化】

    题意略. 离线处理,离散化.然后就是简单的线段树了.需要根据mod 5的值来维护.具体看代码了. /* 线段树+离散化+离线处理 */ #include <cstdio> #include ...

  9. HDU5124:lines(线段树+离散化)或(离散化思想)

    http://acm.hdu.edu.cn/showproblem.php?pid=5124 Problem Description John has several lines. The lines ...

随机推荐

  1. js实现进度条

    不多说,直接上代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  2. 爬虫入门实例:利用requests库爬取笔趣小说网

    w3cschool上的来练练手,爬取笔趣看小说http://www.biqukan.com/, 爬取<凡人修仙传仙界篇>的所有章节 1.利用requests访问目标网址,使用了get方法 ...

  3. Linux 小知识翻译 - 「cron」

    这次说说「cron」. 「cron」就是「定期自动执行任务的工具」(相当于windows中的计划任务).读做「库隆」.使用「cron」,可以预先指定任务在某个时间执行. 时间的指定并不只是「一小时一次 ...

  4. js获取请求地址后面带的参数

    浏览器输入页面地址的时候在后面带有请求参数, 页面加载后需要获取携带的参数, 可以使用js, 在页面加载js的时候获取参数 http://localhost:8080/demo/index.html? ...

  5. 《Java大学教程》—第13章 程序包

    接下来,是第二学期的内容,也是相对深入的Java学习. 自测题:1.    在类的开发过程中,程序包的作用是什么?P321程序包是为了方便定位和部署类,还可以避免将来类之间出现名称冲突. 2.    ...

  6. python 进程介绍 进程简单使用 join 验证空间隔离

    一.多道程序设计技术(详情参考:https://www.cnblogs.com/clschao/articles/9613464.html) 所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行 ...

  7. MySQL高级知识(二)——Join查询

    前言:该篇主要对MySQL中join语句的七种情况进行总结. 0.准备 join主要根据两表或多表之间列的关系,从这些表中进行数据的查询. 首先创建两张表:tb_emp(员工表)和tb_dept(部门 ...

  8. nginx配置文件服务器

    server{ listen  端口号; server_name   localhost; charset utf-8; root    放文件的路径; location   /xxx/yyy/ { ...

  9. BZOJ2124:等差子序列(线段树,hash)

    Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得A ...

  10. JDK动态代理Demo代码,进一步学习分析

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflec ...