POJ1151Atlantis 矩形面积并 扫描线 线段树
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - POJ1151
题意概括
给出n个矩形,求他们的面积并。
n<=100
题解
数据范围极小。
我们分3种算法逐步优化。
算法1: O(n3)
如果这n个矩形的坐标都是整数,而且比较小,那么我们显然可以用最暴力的方法:一个一个打标记。
但是不是这样的。
坐标大小很大,而且是实数。
然而我们发现差不多,只要先离散化一下,然后再打标记即可。
算法2:O(n2)
实际上,上面的方法十分慢。如果n的范围到了1000,上面的就无济于事了。
而实际上,基于上面的打标记的算法,我们可以通过差分的方法n2解决。
我们通过差分,可以用n2的时间标记,n2的时间判断每一个区域是否被覆盖。
空间复杂度O(n2)
算法3:O(n logn) 扫描线
实际上,这类问题的数据范围可以到100000这个级别。
矩形面积并可以用扫描线算法来解决。先看原理,后面讲具体实现。
比如下图:
当前我们的扫描线到达了淡黄色部分。
由于之前没有记录,所以答案不增加。
然而我们记下当前横向覆盖的长度。
然后我们到了第二条扫描线,加上原来记录的横向覆盖长度乘以增加的高度就是当前增加的答案。
然后,我们更新了横向覆盖的长度。
继续。
然后第三条。现在的横向覆盖长度是两边加起来,所以增加的面积是两块了。
然后更新横向覆盖的长度,加上了中间的那一条。
然后继续。
现在有这么长的一条都是被横向覆盖的了。
所以新增的面积是浅蓝色部分。
然后我们发现左上那条线是出边,所以要删除这一条线。
所以横向覆盖的长度为如下:
同理,接下来是:
然后就OK了。
那么具体怎么实现呢?
我们开一棵线段树来维护!
在读入之后,我们把所有的横线都拆开,分成下边和上边两类。某一区间在进入下边的时候+1,离开上边的时候-1,所以我们分别给上下边标记+1和-1。
对于Y,我们离散化一下。
对于X,我们按照边的X排一个序。
然后按照刚才那样的处理。
具体如何维护详见代码。
代码
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=+,M=N*;
const double Eps=1e-;
int T=,n,m,tot_Y,tot_s;
double Y[M];
struct Segment{
double x,L,R;
int v;
void set(double x_,double L_,double R_,int v_){
x=x_,L=L_,R=R_,v=v_;
}
}s[M];
struct SegTree{
int cnt;
double sum;
}t[M*];
bool cmp_s(Segment a,Segment b){
return a.x<b.x;
}
void build(int rt,int le,int ri){
t[rt].cnt=;
t[rt].sum=;
if (le==ri)
return;
int mid=(le+ri)>>,ls=rt<<,rs=ls|;
build(ls,le,mid);
build(rs,mid+,ri);
}
void pushup(int rt,int le,int ri){
int ls=rt<<,rs=ls|;
if (t[rt].cnt)
t[rt].sum=Y[ri+]-Y[le];
else if (le==ri)
t[rt].sum=;
else
t[rt].sum=t[ls].sum+t[rs].sum;
}
void update(int rt,int le,int ri,int xle,int xri,int d){
if (le>xri||ri<xle)
return;
if (xle<=le&&ri<=xri){
t[rt].cnt+=d;
pushup(rt,le,ri);
return;
}
int mid=(le+ri)>>,ls=rt<<,rs=ls|;
update(ls,le,mid,xle,xri,d);
update(rs,mid+,ri,xle,xri,d);
pushup(rt,le,ri);
}
int find_double(double x){
int le=,ri=m,mid;
while (le<=ri){
mid=(le+ri)>>;
if (abs(x-Y[mid])<Eps)
return mid;
if (Y[mid]<x)
le=mid+;
else
ri=mid-;
}
}
int main(){
while (scanf("%d",&n)&&n){
tot_Y=tot_s=;
for (int i=;i<=n;i++){
double xA,yA,xB,yB;
scanf("%lf%lf%lf%lf",&xA,&yA,&xB,&yB);
if (yB-yA<Eps||xB-xA<Eps)
continue;
Y[++tot_Y]=yA,Y[++tot_Y]=yB;
s[++tot_s].set(xA,yA,yB,);
s[++tot_s].set(xB,yA,yB,-);
}
sort(Y+,Y+tot_Y+);
sort(s+,s+tot_s+,cmp_s);
m=;
for (int i=;i<=tot_Y;i++)
if (Y[i]-Y[i-]>Eps)
Y[++m]=Y[i];
build(,,m);
double ans=;
for (int i=;i<=tot_s;i++){
ans=ans+(s[i].x-s[i-].x)*t[].sum;
int L=find_double(s[i].L);
int R=find_double(s[i].R);
update(,,m,L,R-,s[i].v);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",++T,ans);
}
return ;
}
POJ1151Atlantis 矩形面积并 扫描线 线段树的更多相关文章
- 矩形面积并-扫描线 线段树 离散化 模板-poj1151 hdu1542
今天刚看到这个模板我是懵逼的,这个线段树既没有建树,也没有查询,只有一个update,而且区间成段更新也没有lazy标记....研究了一下午,我突然我发现我以前根本不懂扫描线,之所以没有lazy标记, ...
- POJ 1151 Atlantis 矩形面积求交/线段树扫描线
Atlantis 题目连接 http://poj.org/problem?id=1151 Description here are several ancient Greek texts that c ...
- hdu1542 矩形面积并(线段树+离散化+扫描线)
题意: 给你n个矩形,输入每个矩形的左上角坐标和右下角坐标. 然后求矩形的总面积.(矩形可能相交). 题解: 前言: 先说说做这道题的感受: 刚看到这道题顿时就懵逼了,几何 烂的渣渣.后来从网上搜题解 ...
- 【HDU 1542】Atlantis 矩形面积并(线段树,扫描法)
[题目] Atlantis Problem Description There are several ancient Greek texts that contain descriptions of ...
- luogu P1856 [USACO5.5]矩形周长Picture 扫描线 + 线段树
Code: #include<bits/stdc++.h> #define maxn 200007 #define inf 100005 using namespace std; void ...
- HDU 1255 覆盖的面积 (扫描线 线段树 离散化 矩形面积并)
题目链接 题意:中文题意. 分析:纯手敲,与上一道题目很相似,但是刚开始我以为只是把cnt>=0改成cnt>=2就行了,. 但是后来发现当当前加入的线段的范围之前 还有线段的时候就不行了, ...
- 【BZOJ4418】[Shoi2013]扇形面积并 扫描线+线段树
[BZOJ4418][Shoi2013]扇形面积并 Description 给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖. Input 第一行是三个整数n,m,k.n代表同心扇形的个数,m用 ...
- (HDU 1542) Atlantis 矩形面积并——扫描线
n个矩形,可以重叠,求面积并. n<=100: 暴力模拟扫描线.模拟赛大水题.(n^2) 甚至网上一种“分块”:分成n^2块,每一块看是否属于一个矩形. 甚至这个题就可以这么做. n<=1 ...
- HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)
链接:线段树求矩形面积并 扫描线+离散化 1.给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 2.看完线段树求矩形面积并 的方法后,再看这题,求的是矩形面积交,类同. 求面积时,用被覆 ...
随机推荐
- [ZJOI2012]波浪弱化版(带技巧的DP)
题面 \(solution:\) 这道确实挺难的,情况特别多,而且考场上都没想到如何设置状态.感觉怎么设状态不能很好的表示当前情况并转移,考后发现是对全排列的构造方式不熟而导致的,而这一题的状态也是根 ...
- C - Little Jumper (三分)
题目链接:https://cn.vjudge.net/contest/281961#problem/C 题目大意:青蛙能从一个点跳到第三个点,如图,需要跳两次.问整个过程的最大起跳速度中的最小的. 具 ...
- dfs(通过控制点的编号来得出每个点的坐标)
题目链接:https://cn.vjudge.net/contest/234497#problem/A #include<iostream> #include<string> ...
- MGR架构 ~ MGR+proxysql(2)
一 简介: 上篇环境已经搭建完成,我们开始进行测试 二 工具和环境: sysbench ,mgr+proxysql 三 测试方式: sysbench+oltp.lua脚本 四 模拟故障 1 并发环境观 ...
- Linux命令行与shell脚本编程大全.第3版(文字版) 超清文字-非扫描版 [免积分、免登录]
此处免费下载,无需账号,无需登录,无需积分.收集自互联网,侵权通知删除. 点击下载:Linux命令行与shell脚本编程大全.第3版 (大小:约22M)
- iOS视频流开发(2)—视频播放
承上篇,本篇文章主要介绍iOS视频播放需要用到的类.以及他们的使用场景和开发中遇到的问题. MPMoviePlayerViewController MP简介 iOS提供MPMoviePlayerCon ...
- JavaScript中 this 的指向
很多人都会被JavaScript中this的指向(也就是函数在调用时的调用上下文)弄晕,这里做一下总结: 首先,顶层的this指向全局对象. 函数中的this按照调用方法的不同,其指向也不同: 1.函 ...
- BFGS算法(转载)
转载链接:http://blog.csdn.net/itplus/article/details/21897443 这里,式(2.38)暂时不知如何证出来,有哪位知道麻烦给个思路.
- Tengine HTTPS原理解析、实践与调试【转】
本文邀请阿里云CDN HTTPS技术专家金九,分享Tengine的一些HTTPS实践经验.内容主要有四个方面:HTTPS趋势.HTTPS基础.HTTPS实践.HTTPS调试. 一.HTTPS趋势 这一 ...
- mysql系列七、mysql索引优化、搜索引擎选择
一.建立适当的索引 说起提高数据库性能,索引是最物美价廉的东西了.不用加内存,不用改程序,不用调sql,只要执行个正确的'create index',查询速度就可能提高百倍千倍,这可真有诱惑力.可是天 ...