AcWing 247. 亚特兰蒂斯 | 扫描线
题目描述
有几个古希腊书籍中包含了对传说中的亚特兰蒂斯岛的描述。
其中一些甚至包括岛屿部分地图。
但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。
您的朋友Bill必须知道地图的总面积。
你自告奋勇写了一个计算这个总面积的程序。
输入格式
输入包含多组测试用例。
对于每组测试用例,第一行包含整数n,表示总的地图数量。
接下来n行,描绘了每张地图,每行包含四个数字x1,y1,x2,y2x1,y1,x2,y2(不一定是整数),(x1,y1)(x1,y1)和(x2,y2)(x2,y2)分别是地图的左上角位置和右下角位置。
当输入用例n=0时,表示输入终止,该用例无需处理。
输出格式
每组测试用例输出两行。
第一行输出”Test case #k”,其中k是测试用例的编号,从1开始。
第二行输出“Total explored area:a”,其中a是总地图面积(即此测试用例中所有矩形的面积并,注意如果一片区域被多个地图包含,则在计算总面积时只计算一次),精确到小数点后两位数。
在每个测试用例后输出一个空行。
数据范围
1≤n≤100,
0≤x1<x2≤100000,
0≤y1<y2≤100000
输入样例:
2
10 10 20 20
15 15 25 25.5
0
输出样例:
Test case #1
Total explored area: 180.00
题意:求面积并
题解:扫描线。
如果题目给出的矩形如下:
那么我们要求的总面积为:
我们如果用一条竖直的直线从左到右扫过整个坐标系,那么直线上在所求面积中的覆盖长度L只会在每个矩形的左右边界发生变化,整个图形可以被分成2*n段,每一段直线被覆盖的长度L都是固定的,这一段的面积为L*∆x。
我们知道∆x是两个相邻的x之间的间距,那我们要怎么维护每一段L的长度?
对于每个矩形,我们把左边界记为一个四元组:(x1,y1,y2,1),把右边界记为(x2,y1,y2,-1)(假设x1<x2,y1<y2)。我们可以按纵坐标维护一个线段树,当直线扫过矩形的左边界时,相当于在线段树中把区间[y1,y2](y1<y2)的值都加上1(插入区间[y1,y2]),当直线扫过矩形的右边界时,相当于在线段树中把区间[y1,y2]的值都减去1(减去区间[y1,y2]),只要有位置值大于0就代表这是线段的一部分(算区间长度)。因为y的范围很大所以我们要先离散化一下。我们在线段树中定义cnt来记录这段区间出现了多少次,定义len来记录直线长度。每次将直线更新之后,根结点中存的长度就是当前段L的大小。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = + ;
struct node{
double x,y1,y2;
int val;
node() {}
node(double x, double y1, double y2,int val){
this->x = x; this->val = val;
this->y1 = y1; this->y2 = y2;
}
bool operator <(const node &t)const {
return x<t.x;
}
};
struct Tree{
int l,r,cnt;
double len;
}t[]; //找了一个小时的段错误,结果是*4小了???
int n,k=;
vector<node> a;
vector<double> y;
void up(int rt) {
if (t[rt].cnt>) t[rt].len = y[t[rt].r+] - y[t[rt].l];
else t[rt].len = t[rt<<].len + t[rt<<|].len;
}
void build(int rt,int l,int r) {
t[rt].l = l,t[rt].r = r; t[rt].cnt = ;
t[rt].len = ;
if (l == r) return;
int mid = (l+r)>>;
build(rt<<,l,mid);
build(rt<<|,mid+,r);
}
void update(int rt,int l,int r,int val) {
if (l <= t[rt].l && r >= t[rt].r) {
t[rt].cnt+=val;
up(rt);
return;
}
int mid = (t[rt].l+t[rt].r)>>;
if (l <= mid) update(rt<<,l,r,val);
if (r > mid) update(rt<<|,l,r,val);
up(rt);
}
int main() {
while (~scanf("%d",&n) && n) {
y.clear();a.clear();
for(int i = ; i < n; i++) {
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
y.push_back(y1);
y.push_back(y2);
a.push_back(node(x1,y2,y1,));
a.push_back(node(x2,y2,y1,-));
}
y.push_back(-);
sort(a.begin(),a.end());
sort(y.begin(),y.end());
y.erase(unique(y.begin(),y.end()),y.end());
int m = y.size(),num = a.size();
build(,,m);
double ans = ;
for (int i = ; i < num; i++) {
int l = lower_bound(y.begin(),y.end(),a[i].y2)-y.begin();
int r = lower_bound(y.begin(),y.end(),a[i].y1) - y.begin()-;
update(,l,r,a[i].val);
ans += t[].len*(a[i+].x-a[i].x);
}
printf("Test case #%d\n",k++);
printf("Total explored area: %.2f\n\n",ans);
}
return ;
}
PS:注意数组开大一点
AcWing 247. 亚特兰蒂斯 | 扫描线的更多相关文章
- AcWing 247. 亚特兰蒂斯 (线段树,扫描线,离散化)
题意:给你\(n\)个矩形,求矩形并的面积. 题解:我们建立坐标轴,然后可以对矩形的横坐标进行排序,之后可以遍历这些横坐标,这个过程可以想像成是一条线从左往右扫过x坐标轴,假如这条线是第一次扫过矩形的 ...
- AcWing 248. 窗内的星星 (扫描线)打卡
题目:https://www.acwing.com/problem/content/250/ 题意:给你n个点,现在问你能每个点都有个权值,问你能覆盖最多的权值是多少,边界不算 思路:这个其实和我之前 ...
- ACWing 248. 窗内的星星|扫描线+懒惰标记
传送门 题目描述 在一个天空中有很多星星(看作平面直角坐标系),已知每颗星星的坐标和亮度(都是整数). 求用宽为W.高为H的矩形窗户(W,H为正整数)能圈住的星星的亮度总和最大是多少.(矩形边界上的星 ...
- 【学习笔记】线段树—扫描线补充 (IC_QQQ)
[学习笔记]线段树-扫描线补充 (IC_QQQ) (感谢 \(IC\)_\(QQQ\) 大佬授以本内容的著作权.此人超然于世外,仅有 \(Luogu\) 账号 尚可膜拜) [学习笔记]线段树详解(全) ...
- 线段树扫描线(一、Atlantis HDU - 1542(覆盖面积) 二、覆盖的面积 HDU - 1255(重叠两次的面积))
扫描线求周长: hdu1828 Picture(线段树+扫描线+矩形周长) 参考链接:https://blog.csdn.net/konghhhhh/java/article/details/7823 ...
- 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)
D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...
- Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)
题目链接:http://codeforces.com/contest/522/problem/D 题目大意: 给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...
- HUD 4007 [扫描线][序]
/* 大连热身B题 不要低头,不要放弃,不要气馁,不要慌张 题意: 坐标平面内给很多个点,放置一个边长为r的与坐标轴平行的正方形,问最多有多少个点在正方形内部. 思路: 按照x先排序,然后确定x在合法 ...
- Atitit 图像扫描器---基于扫描线
Atitit 图像扫描器---基于扫描线 调用范例 * @throws FileExistEx */ public static void main(String[] args) throws Fil ...
随机推荐
- ArrayList存储基本类型时的封装类
- input submit标签的高度和宽度与input text的差异
<input type="text"> 时设置input的高度和border,最后元素的高度和宽度包含了border的值. <input type="s ...
- 教你怎么让vi和vim显示行数
首先我们来看看没有行号是多么难看. 2 再来看看有行号后的效果. 3 设置行号很简单. 我们要到命令模式下,输入set number :set number 按下回车 来看看效果 4 那么怎么关闭行号 ...
- centos linux mysql 10060远程错误代码
Navicat for MySQL远程连接数据错误代码10060 1.登陆远程linux服务器命令界面 vim /etc/sysconfig/iptables 进入防火墙配置修改 增加以下两条防火墙 ...
- H5 FileReader读取文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- redis cluster和hash slot
redis cluster介绍 从redis3.0.0开始,官方支持了redis cluster的集群模式,结束了redis没有集群的时代. redis cluster 支撑 N 个 redis ma ...
- linux poll 和 select
使用非阻塞 I/O 的应用程序常常使用 poll, select, 和 epoll 系统调用. poll, select 和 epoll 本质上有相同的功能: 每个允许一个进程来决定它是否可读或者写一 ...
- Linux 标准 C 类型的使用
尽管大部分程序员习惯自由使用标准类型, 如 int 和 long, 编写设备驱动需要一些小心 来避免类型冲突和模糊的 bug. 这个问题是你不能使用标准类型, 当你需要"一个 2-字节 填充 ...
- maven仓库总结,maven私服搭建,批量mvn eclipse:eclipse
配置pom.xml依赖包时在这里找包的描述: http://search.maven.org/#browse 以java为根目录. mvn archtype:generate -DgroupId=zt ...
- Linux环境下安装mysql(远程连接),zookeeper,java,tomcat.
环境阿里云centos7.5 64位 + FinalShell + Navicat Permium 12 用到的压缩包(版本看后缀) 注意:安装均在/usr/local目录下,下面代码中#号不要复制上 ...