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

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

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

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

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

从上往下(从下往上也行)我们把每个矩形用一个四元组表示了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. JMeter—总结

    Jmter简单总结 简单的使用篇 jmeter简单的使用 Jmeter中默认语言的显示 jmeter利用自身代理录制脚本 Jmeter运行后出现乱码 http cookie管理中cookie poli ...

  2. sqlserver——cube:多维数据集

    1.cube:生成多维数据集,包含各维度可能组合的交叉表格,使用with 关键字连接 with cube 根据需要使用union all 拼接 判断 某一列的null值来自源数据还是 cube 使用G ...

  3. cmd输出控制台传递的参数

    public class Test2{ public static void main(String[] args){ System.out.println(args[0]); System.out. ...

  4. visual studio 的git插件推荐

    TGit 支持vs 2013/15/17及更高版本,需要搭配 TortoiseGit 和 MSysGit 一起使用,当然这两者也是我在windows下使用git的推荐组合. 历史版本的diff查看使用 ...

  5. March 11th, 2018 Week 11th Sunday

    All good things must come to an end. 好景无常. Love is when the other person's happiness is more importa ...

  6. 【Teradata】移动空间语句

    1.移动10G空间从sysdba到dbc create database td_tmp_db from sysdba as perm=10E9; give td_tmp_db to "dbc ...

  7. input accept属性限制文件上传格式

    上传文件的类型:具体做法如下所示: 注意:accept属性可以限制上传格式,其有兼容性如下 <1>上传.csv格式的 <input text="file" acc ...

  8. MySQL高级知识(十)——批量插入数据脚本

    前言:使用脚本进行大数据量的批量插入,对特定情况下测试数据集的建立非常有用. 0.准备 #1.创建tb_dept_bigdata(部门表). create table tb_dept_bigdata( ...

  9. ansible的模块使用说明

    参考官方链接: https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html#parallelism-and-shell-co ...

  10. 【转】如何使用分区助手完美迁移系统到SSD固态硬盘?

    自从SSD固态硬盘出世以来,一直都被持续关注着,SSD的性能优势让无数用户起了将操作系统迁移到SSD的心思,直接后果就是让无数机械硬盘为止黯然退场,很多软件都可以做到系统迁移,然而,被完美迁移的系统却 ...