【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 ...
随机推荐
- laravle 事务
DB::beginTransaction(); try{ $name = 'abc'; $result1 = Test::create(['name'=>$name]); ...
- Java练习 SDUT-3849_分数四则运算
分数四则运算 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 编写程序,实现两个分数的加减法 Input 输入包含多行数 ...
- JavaWeb登录、注销、退出、记住用户名和密码
应该是保存在Cookie里,session是放在服务器的内存里的.在用户关闭了网页窗口后,session就清空了.而Cookie是保存在用户的IE临时文件夹中的,再次登录时,读取其中的值传给服务器. ...
- this 、静态变量
/*作者:qingfeng日期:2017/2/18功能:this,静态变量(类变量)*/class Demo3_2{ public static void main(String args[]) ...
- Android 在图片的指定位置添加标记
这些天,项目里加了一个功能效果,场景是: 假如有一个家居图片,图片里,有各样的家居用品: 桌子,毛巾,花瓶等等,需要在指定的商品处添加标记,方便用户直接看到商品,点击该标记,可以进入到商品详情页 .实 ...
- oracle函数 NLS_UPPER(x[,y])
[功能]返回字符串并将字符串的转换为大写; [参数]x字符型表达式 [参数]Nls_param可选,指定排序的方式(nls_sort=) . SCHINESE_RADICAL_M(部首.笔画) SCH ...
- WPS修订功能的使用
WPS设置 设置用户名: 修改之后的效果:
- Core Data 数据出现Fault
I am mapping Json Data from Server using Restkit and I am Displaying those data by fetching from db. ...
- iptables发布内部网络服务器
要使因特网上的计算机访问到内部网的FTP服务器.WEB服务器,在做为防火墙的计算机上应添加以下规则: 1. echo 1 > /proc/sys/net/ipv4/ip_forward 2. 发 ...
- 理解和实现分布式TensorFlow集群完整教程
手把手教你搭建分布式集群,进入生产环境的TensorFlow 分布式TensorFlow简介 前一篇<分布式TensorFlow集群local server使用详解>我们介绍了分布式Ten ...