【42.49%】【hdu 1542】Atlantis(线段树扫描线简析)
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11558 Accepted Submission(s): 4910
Problem Description
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
Input
The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.
The input file is terminated by a line containing a single 0. Don’t process it.
Output
For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.
Output a blank line after each test case.
Sample Input
2
10 10 20 20
15 15 25 25.5
0
Sample Output
Test case #1
Total explored area: 180.00
Source
Mid-Central European Regional Contest 2000
【题解】
给定几个矩形的左下角和右上角;求所有矩形的面积(重复部分不能多算);
线段树,扫描线;
扫描线的思路就是假想一条线段从图的最下面往上扫描;
我们计算的是扫描线扫过的所有矩形区域的面积;
盗下图
需要把横坐标离散化下;
然后处理出每个矩形的两条横边(上边和下边,上边记为-1,下边记为1);
然后记录所有横边的纵坐标;
然后以所有横边的纵坐标作为关键字升序排下;
从纵坐标小的开始处理;
处理到①的时候;看下②的高度是多少
然后看一下①->②这个线段范围内;横坐标有哪些区域被矩形占据了;
求出这个占据的长度sum[1](即线段树的第一个节点
然后答案递增sum[1]*(h②-h①);
处理下一条线段;
如果下一条线段是上边。就把它相应的下边对应的横坐标范围减去;下次就不会再处理了;
嘛,多看下代码结合图理解下吧。不会很难
代码中cnt是这个区间内下边比上边多多少条边;
显然如果cnt[rt]==0则表示这个区间内没有需要处理的矩形覆盖的范围;
大于0则表示有一个矩形覆盖到了这个区间。且还没有处理完;
(处理到上边的时候会减去相应下边这段的cnt值);
sum[rt]则表示这个区间内被矩形覆盖的线段长度;
/*
看完代码之后你们可能会对那个r+1和r-1有点疑问;
这样先对询问把r减去1,是为了防止线段树在划分的时候
出现
1-6
被分成
1-5和6..6的情况;
右边那个区间只有1个点;而我们没办法用x[6]-x[6]来表示这段长度;
而左边是a[5]-a[1];显然会少掉一段5..6没被加进去;
因此我们先减去1;
这样就只会分成
1..5这一段;
然后加的时候改为a[6]-a[1]即可;
即a[r+1]-a[l];
*/
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <string>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
using namespace std;
const int MAXN = 200+10;
const int dx[5] = {0,1,-1,0,0};
const int dy[5] = {0,0,0,-1,1};
const double pi = acos(-1.0);
struct hx
{
double l,r,h,k;
};
int n,num = 0,cnt[MAXN<<2];
double sum[MAXN<<2];
vector <double> a;
hx bian[MAXN];
void input_LL(LL &r)
{
r = 0;
char t = getchar();
while (!isdigit(t) && t!='-') t = getchar();
LL sign = 1;
if (t == '-')sign = -1;
while (!isdigit(t)) t = getchar();
while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
r = r*sign;
}
void input_int(int &r)
{
r = 0;
char t = getchar();
while (!isdigit(t)&&t!='-') t = getchar();
int sign = 1;
if (t == '-')sign = -1;
while (!isdigit(t)) t = getchar();
while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
r = r*sign;
}
bool cmp(hx a,hx b)
{
return a.h<b.h;
}
void up_data(int L,int R,int c,int l,int r,int rt)
{
if (L<=l && r<=R)
{
cnt[rt]+=c;
if (cnt[rt])
sum[rt] = a[r+1]-a[l];
else//变成0了也不能认定内部就没有需要处理的区间了;还要加上内部的;
if (l==r)
sum[rt]=0;
else
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
return;
}
int m = (l+r)>>1;
if (L <= m)
up_data(L,R,c,lson);
if (m < R)
up_data(L,R,c,rson);
if (cnt[rt])//有可能内部下边已经处理完了,但是外部还有下边,所以不能直接写成sum[rt]=sum[rt<<1]+sum[rt<<1|1]
sum[rt] = a[r+1]-a[l];
else
if (l==r)
sum[rt] == 0;
else
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
int main()
{
//freopen("F:\\rush.txt","r",stdin);
input_int(n);
int tt = 0;
while (n!=0)
{
memset(cnt,0,sizeof(cnt));
memset(sum,0,sizeof(sum));
a.clear();num = 0;
for (int i = 1;i <= n;i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
a.push_back(x1);
a.push_back(x2);
num++;
bian[num].l = x1,bian[num].r = x2,bian[num].h = y1,bian[num].k = 1;//横线的下边
num++;
bian[num].l = x1,bian[num].r = x2,bian[num].h = y2,bian[num].k = -1;//记录横线的上边
}
sort(a.begin(),a.end());
a.erase(unique(a.begin(),a.end()),a.end());//x轴离散化
sort(bian+1,bian+1+num,cmp);
double ans = 0;
for (int i = 1;i <= num-1;i++)
{
int l = lower_bound(a.begin(),a.end(),bian[i].l)-a.begin();
int r = lower_bound(a.begin(),a.end(),bian[i].r)-a.begin()-1;//先把右端点-1
up_data(l,r,bian[i].k,0,a.size()-1,1);
ans+=sum[1]*(bian[i+1].h-bian[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n",++tt,ans);
input_int(n);
}
return 0;
}
【42.49%】【hdu 1542】Atlantis(线段树扫描线简析)的更多相关文章
- HDU 1542 - Atlantis - [线段树+扫描线]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Time Limit: 2000/1000 MS (Java/Others) Memory Li ...
- HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- hdu 1542 Atlantis (线段树扫描线)
大意: 求矩形面积并. 枚举$x$坐标, 线段树维护$[y_1,y_2]$内的边是否被覆盖, 线段树维护边时需要将每条边挂在左端点上. #include <iostream> #inclu ...
- hdu 1542 Atlantis(线段树,扫描线)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- HDU 1542 Atlantis(线段树面积并)
描述 There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. S ...
- POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线 ...
- Atlantis HDU - 1542 (线段树扫描线)
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some ...
- hdu 1542(线段树+扫描线 求矩形相交面积)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- hdu 1542 Atlantis(段树&扫描线&面积和)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
随机推荐
- C++ 标准库 permutation
首先,permutation指的是对元素的重排,比方a , b , c 三个元素的全部的重排为 abc, acb, bac,bca,cab,cba 总共 3! = 6 中情况,可是怎样声称这六 ...
- 【机器学习】Iris Data Set(鸢尾花数据集)
[机器学习]Iris Data Set(鸢尾花数据集) 注:数据是机器学习模型的原材料,当下机器学习的热潮离不开大数据的支撑.在机器学习领域,有大量的公开数据集可以使用,从几百个样本到几十万个样本的数 ...
- & 和 | 和 ~
O(∩_∩)O~~浅理解,不足之处请多指正,谢谢. 1) & & :二目运算符,把运算符两侧的数换成 二进制 再依次求与. 例如:a = 2,b = 3; c = a & b; ...
- React Native开源项目如何运行(附一波开源项目)
学习任何技术,最快捷的方法就是学习完基础语法,然后模仿开源项目进行学习,React Native也不例外.React Native推出了1年多了, 开源项目太多了,我们以其中一个举例子.给大家演示下如 ...
- day15 web前端之css
css的概念以及初体验 概念: CSS(cascading style sheet)也就是层叠样式表:它是一种网页设计的新技术,现在已经被大多数浏览器所支持,层位网页设计必不可少的工具之一.优点: ...
- Windows server 2012 开启消息队列功能
- 2019-2-2-VisualStudio-扩展开发-添加菜单
title author date CreateTime categories VisualStudio 扩展开发 添加菜单 lindexi 2019-02-02 15:35:18 +0800 201 ...
- Oracle dbms_random包的用法
1.dbms_random.value方法 dbms_random是一个可以生成随机数值或者字符串的程序包.这个包有initialize().seed().terminate().value().no ...
- oracle函数 LOWER(c1)
[功能]:将字符串全部转为小写 [参数]:c1,字符表达式 [返回]:字符型 [示例] SQL> select lower('AaBbCcDd')AaBbCcDd from dual; AABB ...
- 同一个C语言工程不同C文件之间的函数互相调用问题
定义一个function.h文件来声明这些函数: //#ifndef __FUNCTION_H__//#define __FUNCTION_H__ int fun(int,int); int ...