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

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

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

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

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

从上往下(从下往上也行)我们把每个矩形用一个四元组表示了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. c/c++ 模板与STL小例子系列<三> traits

    c/c++ 模板与STL小例子系列 traits 对这个概念,还是处于懵逼的状态,初步体会就是,为了解决类型之间的转换问题. 从一个类型为A的指针,转化到类型为B的指针,中间需要用void*来作为中介 ...

  2. c/c++ new delete初探

    new delete初探 1,new有2个作用 开辟内存空间. 调用构造函数. 2,delete也有2个作用 释放内存空间 调用析构函数. 如果用new开辟一个类的对象的数组,这个类里必须有默认(没有 ...

  3. c/c++链队列

    链队列 链队列就是简化了的单链表 nodequeue.h #ifndef __NODEQUEUE__ #define __NODEQUEUE__ #include <stdio.h> #i ...

  4. echo 在shell及脚本中显示色彩及闪烁警告效果

    在shell脚本编写中,echo用于输出字符串等提示信息,当我们需要格外显示色彩及闪烁效果如下: 一.在执行shell中显示色彩: 语法格式: echo -e "\033[颜色1:颜色2m ...

  5. vCenter server 的部署和实施

    上一次我们讲解了vclient 5.5 的安装以及连接ESXI5.5,但vclient只能管理一台ESXI,管理多台还需要切换登陆,非常麻烦.所以这次我们就来讲解一下vcenter server的相关 ...

  6. Linux 小知识翻译 - 「代理服务器」

    这回聊聊「代理服务器」. 在公司里,不通过代理服务器无法连接互联网的,由于代理服务器的原因,有些服务的使用是受到限制的. 有人可能会觉得为什么会存在这种东西?(这里指代理服务器) Proxy本来的意思 ...

  7. ES5-ES6-ES7_Symbol数据类型

    Symbol数据类型简介 ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值.它是 JavaScript 语言的第七种数据类型,前六种是:undefined.null.布尔值(Boole ...

  8. 解决新版chrome无法手动拖动安装插件 提示“无法从该网站添加应用,扩展程序和用户脚本”

    开发模式安装 把下载后的.crx扩展名的离线Chrome插件的文件扩展名改成.zip或者.rar 解压压缩文件 在Chrome的地址栏中输入:chrome://extensions/ 打开Chrome ...

  9. php 验证身份证号

    function validation_filter_id_card($id_card){ if(strlen($id_card)==18){ return idcard_checksum18($id ...

  10. linux+node.js+redis+mongodb+nginx环境的搭建

    1.推荐购买阿里云服务器,使用Centos7.0的服务器版本,在创建完全系统并进入之后,第一步是更新服务器的相关组件    yum -y install gcc gcc-c++ openssl-dev ...