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(线段树扫描线简析)的更多相关文章

  1. HDU 1542 - Atlantis - [线段树+扫描线]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Time Limit: 2000/1000 MS (Java/Others) Memory Li ...

  2. HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  3. hdu 1542 Atlantis (线段树扫描线)

    大意: 求矩形面积并. 枚举$x$坐标, 线段树维护$[y_1,y_2]$内的边是否被覆盖, 线段树维护边时需要将每条边挂在左端点上. #include <iostream> #inclu ...

  4. hdu 1542 Atlantis(线段树,扫描线)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  5. HDU 1542 Atlantis(线段树面积并)

     描述 There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. S ...

  6. POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并

    题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线 ...

  7. Atlantis HDU - 1542 (线段树扫描线)

    There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some ...

  8. hdu 1542(线段树+扫描线 求矩形相交面积)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  9. hdu 1542 Atlantis(段树&amp;扫描线&amp;面积和)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

随机推荐

  1. ACK容器服务虚拟节点使用阿里云日志服务来收集业务容器日志

    按照这篇博文的介绍,可以在ACK集群上通过Helm的方式部署虚拟节点,提升集群的弹性能力.现在,通过虚拟节点部署的ECI弹性容器实例也支持将stdout输出.日志文件同步到阿里云日志服务(SLS)进行 ...

  2. Android实战:手把手实现“捧腹网”APP(三)-----UI实现,逻辑实现

    Android实战:手把手实现"捧腹网"APP(一)-–捧腹网网页分析.数据获取 Android实战:手把手实现"捧腹网"APP(二)-–捧腹APP原型设计.实 ...

  3. execute和submit的区别与联系

    execute和submit都属于线程池的方法,execute只能提交Runnable类型的任务,而submit既能提交Runnable类型任务也能提交Callable类型任务. execute会直接 ...

  4. php 正则学习取反符号~

    php 正则学习取反符号~ ~(<a .*?>.*?</a>|<.*?>)~i 先看正则图形,有点偏差,但可以初步看出结果. 关于 ~ 是取反符号,看下面说明.

  5. ffmpeg在iOS的使用 - iFrameExtractor源码解析

    http://www.cocoachina.com/ios/20150914/13284.html iFrameExtractor地址:https://github.com/lajos/iFrameE ...

  6. @hdu - 6687@ Rikka with Stable Marriage

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个稳定婚姻匹配问题,其中第 i 个男生与第 j 个女生之间 ...

  7. 10-1 body标签里面相关的标签(列表,表单,表格)

    一 列表标签<ul>,<ol>,<dl> <!DOCTYPE html> <html lang="en"> <he ...

  8. 洛谷P1616 疯狂的采药

    //完全背包 #include<bits/stdc++.h> using namespace std; ; ; int n,m,v[maxn],w[maxn],f[maxv]; int m ...

  9. iptables 防止DoS攻击

    SYN洪水是攻击者发送海量的SYN请求到目标服务器上的一种DoS攻击方法,下面的脚本用于预防轻量级的DoS攻击:ipt-tcp.sh: iptables -N syn-flood (如果您的防火墙默认 ...

  10. 2016 年度开源中国新增开源软件排行榜 TOP 100

    2016 年度开源中国新增开源软件排行榜 TOP 100 2016 年度开源中国新增开源软件排行榜 TOP 100 新鲜出炉!本榜单根据 2016 年开源中国新收录的 3030 款软件的关注度和活跃度 ...