【题解】codevs 3044 矩形面积合并
3044 矩形面积求并
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
题目描述 Description
输入n个矩形,求他们总共占地面积(也就是求一下面积的并)
输入描述 Input Description
可能有多组数据,读到n=0为止(不超过15组)
每组数据第一行一个数n,表示矩形个数(n<=100)
接下来n行每行4个实数x1,y1,x2,y1(0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000),表示矩形的左下角坐标和右上角坐标
输出描述 Output Description
每组数据输出一行表示答案
样例输入 Sample Input
2
10 10 20 20
15 15 25 25.5
0
样例输出 Sample Output
180.00
数据范围及提示 Data Size & Hint
无
前言:
先是在《高级数据结构》上看到了这道例题,然而各种指针蒟蒻的我根本看不惯;昨天老师又讲了一下这道题,然而蒟蒻的我还是没懂。蒟蒻的我又看了一下黄学长(orz)的博客,然后......我就好像懂了。然而敲了一小时代码,运行时忽然发现卡入循环无法自拔,到今天早上忽然发现一个玄学错误,把二分查找带入一个参数终于能正常运行。然而又发现样例都过不了,又不断调试,调了一个小时,找了几处错误,终于AC了,要是在考场上我怕是要van了。
分析:
首先先不考虑什么离散化,线段树之类的,先想主要的算法。
我们假想一根扫描线(在这里假设它平行于x轴),从下往上扫,扫到一条边就在它在一根数轴上的投影上打上标记,假如已被覆盖那就只用加上标记,没被覆盖就还要让一个记录长度总和的变量加上长度,然后请用长度的总和乘以与下一条边的高度差。同时如果该边是矩形的上边的话那就在扫描后删去这条边的标记。然后再逐一考虑细节,首先我们可以用数组暴力模拟覆盖标记过程,当然为了最优我们选择线段树。
接着就有一个大问题,它给出的坐标是实数而非整数,这样线段树树或数组就不可能对应x轴的每一个端点,怎么办呢?用离散化,首先我们是要搞一个数组存各个点的横纵坐标对吧,我们再搞一个数组node存各个横坐标,然后将这个node从小到大排序,我们就把这个node数组每一个下标看做线段的端点,实际上我们也知道小的下标存小的横坐标,大的下标存大的横坐标。虽然理解起来可能有点困难,但这确实是个非常有用的技巧。
同时我们还有一些问题要注意,每一次我们扫描是要知道这条新边的左右两个端点横坐标来加标记,所以我们可以在记录横纵坐标的数组里将两个横坐标都记录,再搞一个标记判断它是上边还是下边。
代码实现:
要是看不懂我这个蒟蒻写的话就看代码吧,多想多画几遍就理解了。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100010;
double sum[maxn<<2];
double node[maxn<<2]; //离散化,存x1,线段树的总区间是下标,
//但我们要给它排序,使得小的下标对小的x
//符合区间加法,这样才可以使用线段树
int n,k;
int ok[maxn<<1];//标记
int L,R;
double ans=0;
struct Dot{
double x1,x2,y;
short int opt;
}dot[maxn];
bool cmp(Dot a,Dot b){
return a.y<b.y;
}
int binary_search(double t,int lim){
int l=1,r=lim*2;
int ans;
while(l<=r)
{
int mid=(l+r)>>1;
if(node[mid]==t){
ans=mid;break;
}
else if(node[mid]>t)r=mid-1;
else l=mid+1;
}
return ans;
}
void pushup(int now,int l,int r)
{
if(ok[now])sum[now]=node[r+1]-node[l];
else if(l==r) sum[now]=0;//递归到叶节点且无覆盖
else sum[now]=sum[now<<1]+sum[now<<1|1];
}
void update(int now,int l,int r)
{
if(L<=l&&r<=R){
ok[now]+=k;
pushup(now,l,r);
return ;
}
int mid=(l+r)>>1;
if(L<=mid)update(now<<1,l,mid);
if(R>mid)update(now<<1|1,mid+1,r);
pushup(now,l,r);
return;
}
int main()
{
int n;
while(1){
double x1,x2,y1,y2;
scanf("%d",&n);
if(!n)return 0;
for(int i=1;i<=n;i++){
int d=(i<<1)-1,u=(i<<1);
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
dot[d].x1=x1;//下边
dot[d].x2=x2;
dot[d].y=y1;
dot[d].opt=1;
dot[u].x1=x1;//上边
dot[u].x2=x2;
dot[u].y=y2;
dot[u].opt=-1;
node[d]=x1;//离散化
node[u]=x2;
}
sort(dot+1,dot+1+(n<<1),cmp);
sort(node+1,node+1+(n<<1));
for(int i=1;i<=(n<<1)-1;i++){
//debug cout<<n<<endl;
L=binary_search(dot[i].x1,n);
R=binary_search(dot[i].x2,n)-1;
//因为已离散化,我们需二分查找
k=dot[i].opt;
update(1,1,2*n);
ans+=(dot[i+1].y-dot[i].y)*sum[1];
}
printf("%.2lf\n",ans);
ans=0; //一定要初始化
memset(sum,0,sizeof(sum));
memset(ok,0,sizeof(ok));
memset(dot,0,sizeof(dot));
}
return 0;
}
【题解】codevs 3044 矩形面积合并的更多相关文章
- codevs 3044 矩形面积求并
3044 矩形面积求并 题目描述 Description 输入n个矩形,求他们总共占地面积(也就是求一下面积的并) 输入描述 Input Description 可能有多组数据,读到n=0为止(不 ...
- poj1151==codevs 3044 矩形面积求并
Atlantis Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 21511 Accepted: 8110 Descrip ...
- codevs 3044 矩形面积求并 (扫描线)
/* 之前一直偷懒离散化+暴力做着题 今天搞一下扫描线 自己按照线段树的一般写法写的有些问题 因为不用于以前的区间sum so 题解搬运者23333 Orz~ 去掉了打标记的过程 同时更新区间的时候先 ...
- codevs 3044 矩形面积求并 || hdu 1542
这个线段树的作用其实是维护一组(1维 平面(?) 上的)线段覆盖的区域的总长度,支持加入/删除一条线段. 线段树只能维护整数下标,因此要离散化. 也可以理解为将每一条处理的线段分解为一些小线段,要求每 ...
- codves 3044 矩形面积求并
codves 3044 矩形面积求并 题目等级 : 钻石 Diamond 题目描述 Description 输入n个矩形,求他们总共占地面积(也就是求一下面积的并) 输入描述 Input Desc ...
- 3044 矩形面积求并 - Wikioi
题目描述 Description 输入n个矩形,求他们总共占地面积(也就是求一下面积的并) 输入描述 Input Description 可能有多组数据,读到n=0为止(不超过15组) 每组数据第一行 ...
- [Codevs] 矩形面积求并
http://codevs.cn/problem/3044/ 线段树扫描线矩形面积求并 基本思路就是将每个矩形的长(平行于x轴的边)投影到线段树上 下边+1,上边-1: 然后根据线段树的权值和与相邻两 ...
- 【HDU 1542】Atlantis 矩形面积并(线段树,扫描法)
[题目] Atlantis Problem Description There are several ancient Greek texts that contain descriptions of ...
- Largest Rectangle in a Histogram(最大矩形面积,动态规划思想)
Largest Rectangle in a Histogram Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 ...
随机推荐
- vuejs2从入门到精通与项目开发实战
vuejs2从入门到精通:一.基础部分0.课件1.介绍2.vue实例3.模板语法4.计算属性和观察者5.Class与Style绑定6.条件渲染7.列表渲染8.事件处理9.表单输入绑定10.1.组件(1 ...
- js回调函数(callback)(转载)
学习jquery时,对回调函数感觉很困惑,在晚上找了半天,忽然发现这篇文章很浅显,基本说明了问题.故转载 原文: 自学jquery的时候,看到一英文词(Callback),顿时背部隐隐冒冷汗.迅速go ...
- UML建模综述
一.概念 UML-Unified Model Language 统一建模语言,又称标准建模语言.是用来对软件密集系统进行可视化建模的一种语言.作为一个支持模型化和软件系统开发的图形化语言,UML为软件 ...
- 1.2 Go语言基础之变量和常量
变量和常量是编程中必不可少的部分,也是很好理解的一部分. 一.标识符与关键字 1.1 标识符 在编程语言中标识符就是程序员定义的具有特殊意义的词,比如变量名.常量名.函数名等等. Go语言中标识符由字 ...
- smb服务问题解析,区别红帽6和CentOS7
最近在学习smb服务,哇!简直问题多的不要不要的.因为以前是学习的红帽6的系统,现在用的是CentOs7,所以还是改不了以前的一些配置方式,造成了很多问题.快成地中海了! 我们准备环境: 系统: 服务 ...
- 开机自动挂载ISO文件
开机自动挂载ISO文件 Table of Contents 1. 概述 1.1. 通过fstab 1.2. 通过rc.local 1 概述 开机自动挂载ISO 文件有两种途径 .一种是通过配置fsta ...
- LVS系列二、LVS集群-DR模式
一. LVS-DR和LVS-IP TUN集群概述 1. Direct Routing(直接路由) Director分配请求到不同的real server.real server处理请求后直接回应给用 ...
- KDE-解决.docx .xlsx .pptx文档默认由Ark打开的问题
安装KDE后,默认的压缩解压程序变成了Ark,并且原来默认用WPS Office打开的.docx .xlsx .pptx文档,从文件管理器双击打开时,也变成了用Ark打开. 查了下网上的资料,可通过如 ...
- centos7操作
一.安装系统 1.下载(Minimal ISO)http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-1 ...
- 树莓派(Linux)添加USB外接硬盘
1.显示系统的硬盘设备以及分区 sudo fdisk -l 显示设备名,例如/dev/sda1 2.树莓派默认不支持NTFS文件系统,如果需要支持则要安装相应的软件包 sudo apt-get ins ...