HDU - 1542 扫描线入门+线段树离散化
扫描线算法+线段树维护简介:
像这种求面积的并集的题目,就适合用扫描线算法解决,具体来说就是这样
类似这种给出点的矩形的对角的点的坐标,然后求出所有矩形面积的交集的问题,可以采用扫描线算法解决。图如下,我们要求红色部分的面积:
我们可以通过一条叫扫描线的东西解决问题。具体来说:
我们首先给自己一条线,这条可以我称之为标准线(棕色线表示)
从上往下(从下往上也行)我们把每个矩形用一个四元组表示了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 扫描线入门+线段树离散化的更多相关文章
- HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- 【42.49%】【hdu 1542】Atlantis(线段树扫描线简析)
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...
- 【HDU】5249-KPI(线段树+离散化)
好久没写线段树都不知道怎么写了... 很easy的线段树二分问题 #include<cstdio> #include<set> #include<queue> #i ...
- HDU 1542"Atlantis"(线段树+扫描线求矩形面积并)
传送门 •题意 给你 n 矩形,每个矩形给出你 $(x_1,y_1),(x_2,y_2)$ 分别表示这个矩形的左下角和右上角坐标: 让你求这 n 个矩形并的面积: 其中 $x \leq 10^{5} ...
- HDU - 1542 Atlantis(线段树求面积并)
https://cn.vjudge.net/problem/HDU-1542 题意 求矩形的面积并 分析 点为浮点数,需要离散化处理. 给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1).(x ...
- hdu1542 矩形面积并(线段树+离散化+扫描线)
题意: 给你n个矩形,输入每个矩形的左上角坐标和右下角坐标. 然后求矩形的总面积.(矩形可能相交). 题解: 前言: 先说说做这道题的感受: 刚看到这道题顿时就懵逼了,几何 烂的渣渣.后来从网上搜题解 ...
- 【POJ 2482】 Stars in Your Window(线段树+离散化+扫描线)
[POJ 2482] Stars in Your Window(线段树+离散化+扫描线) Time Limit: 1000MS Memory Limit: 65536K Total Submiss ...
- HDU 4288 Coder 【线段树+离线处理+离散化】
题意略. 离线处理,离散化.然后就是简单的线段树了.需要根据mod 5的值来维护.具体看代码了. /* 线段树+离散化+离线处理 */ #include <cstdio> #include ...
- HDU5124:lines(线段树+离散化)或(离散化思想)
http://acm.hdu.edu.cn/showproblem.php?pid=5124 Problem Description John has several lines. The lines ...
随机推荐
- MyBatis笔记----报错:Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/ij34/mybatis/applicationContext.xml]: Invocation of init method failed; nested exception is org.sp
四月 05, 2017 4:51:02 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRef ...
- c#判断两个对象和对象中的属性是否相同(以及记录对象中的哪些字段,和详细的改变情况)
当前项目需要记录变更记录,即用户在进行编辑后,将变更操作记录下来.但是数据没有发生变化,则不记录. 代码1:(仅仅返回是否变化的标识) /// <summary> /// 反射对比实体属性 ...
- MySQl ifnull()和substr()
SUBSTR(str,pos,len) substr用来截取字符串: str 被截取的字符串 pos 开始位置 len 长度 举个例子: substr('abc',1,2)='ab' IFNULL(e ...
- Echars鼠标点击事件多次触发
gChart.on('click', function (params) { if (params.componentSubType == "bar" && par ...
- Windows Server 2016-Windows Server Backup功能
一.Windows Server Backup 介绍: Windows Server Backup 是一种功能,它提供了一组向导和其他工具,大概从WinSer2008开始Win Ser Backup引 ...
- Hadoop2.7.6_01_部署
1. 主机规划 主机名称 外网IP 内网IP 操作系统 备注 安装软件 mini01 10.0.0.11 172.16.1.11 CentOS 7.4 ssh port:22 Hadoop [Name ...
- Socket引子
=== ''' Socket网络编程: --应用层:http smtp dns ftp ssh snmp dhcp... 无论协议是什么本质上都是数据交换,总结为两种方式:收和发 --传输层(端口Po ...
- ES5-ES6-ES7_严格模式
运行模式 正常(混杂)模式与严格模式,除了正常运行模式(混杂模式),ES5添加了第二种运行模式:"严格模式"(strict mode) 顾名思义,这种模式使得Javascript在 ...
- mac下安装redis详细步骤
Linux下安装redis也可以参照下面的步骤哦!!!! 1.到官网上下载redis,我下载的版本是redis-3.2.5.tar 官网地址:http://redis.io/ 2.将下载下来的tar. ...
- Insert Into 语句的语法错误
错误示意: 一开始程序是: 改正: 一条很简单的插入语句竟然会报错,然而直接在数据库的查询中执行中却没有问题,这个问题困扰了不少时间. 数据库使用的是ACCESS,INSERT INTO语句为inse ...