Atlantis

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11551    Accepted Submission(s): 4906

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 (0<=x1<x2<=100000;0<=y1<y2<=100000), 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
 

题目链接:HDU 1542

感觉难点就在如何用点树实现线段上的统计,首先这题是浮点数,肯定要离散化建树(我选的是对X坐标离散化),二分寻找下标当作区间[l,r]。

现在假设有两个区间段:1——2——3 与 3——4——5,但是如果用点树的方式进行更新对前面一个区间+1,后面一个区间-1,那会造成3这个点的覆盖次数变成0,但显然这两个区间在“段”上是连续的,这样更新肯定会出现问题,但是习惯上是写点树而不是段树,那只能对点修改一下,把更新区间的右端R减掉1,每个点表示这个点到后一个点的一段因此前面的两个区间变成了[1,2]与[3,4],这样在点上就不会出现重复的问题了,然后另外一点改动就是在pushup时直接向上传递不用pushdown。

举个例子

$$\begin{array}{c|lll}
{下标}&{0}&{1}&{2}&{3}&{4}&{5}\\
\hline
{实际值}&{3.3}&{9.8}&{12.1}&{19.8}&{24.9}&{33.3}\\
\end{array}$$

这样的一个坐标离散化这时候出现一个线段[9.8~12.1],然后对应离散化的是[1,2-1]即[1,1],但统计len的时候显然是用12.1-9.8=2.3,因此统计时要用X[R+1]-X[L]来作为长度即X[2]-X[1],那这看起来似乎跟前面的刻意把右端点改成R-1矛盾了……既然统计要R+1那前面干嘛要R-1,其实R-1为的是不影响线段树的区间覆盖,但是你是知道实际上要用R来算,由于统计时是不会影响区间覆盖的,因此要还原回去即R=(R-1)+1

代码:

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=110;
struct seg
{
int l,mid,r;
int cnt;
double len;
};
struct Line
{
double l,r,h,flag;
bool operator<(const Line &t)const
{
return h<t.h;
}
};
seg T[N<<3];
Line line[N<<1];
double xpos[N<<1]; inline void pushup(int k)
{
if(T[k].cnt)
T[k].len=xpos[T[k].r+1]-xpos[T[k].l];
else
{
if(T[k].l==T[k].r)
T[k].len=0;
else
T[k].len=T[LC(k)].len+T[RC(k)].len;
}
}
void build(int k,int l,int r)
{
T[k].l=l;
T[k].r=r;
T[k].mid=MID(l,r);
T[k].len=0.0;
T[k].cnt=0;
if(l==r)
return ;
build(LC(k),l,T[k].mid);
build(RC(k),T[k].mid+1,r);
}
void update(int k,int l,int r,int flag)
{
if(l<=T[k].l&&T[k].r<=r)
{
T[k].cnt+=flag;
pushup(k);
}
else
{
if(r<=T[k].mid)
update(LC(k),l,r,flag);
else if(l>T[k].mid)
update(RC(k),l,r,flag);
else
update(LC(k),l,T[k].mid,flag),update(RC(k),T[k].mid+1,r,flag);
pushup(k);
}
}
int main(void)
{
int n,i,q=1;
double xa,xb,ya,yb;
while (~scanf("%d",&n)&&n)
{
int cnt_line=0;
for (i=0; i<n; ++i)
{
scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
xpos[cnt_line]=xa;
line[cnt_line]=(Line){xa,xb,ya,1};
++cnt_line;
xpos[cnt_line]=xb;
line[cnt_line]=(Line){xa,xb,yb,-1};
++cnt_line;
}
sort(xpos,xpos+cnt_line);//X轴坐标排序
sort(line,line+cnt_line);//线段排序 build(1,0,cnt_line); double res=0.0,dh;
int l,r;
for (i=0; i<cnt_line-1; ++i)
{
l=lower_bound(xpos,xpos+cnt_line,line[i].l)-xpos;
r=lower_bound(xpos,xpos+cnt_line,line[i].r)-xpos;
update(1,l,r-1,line[i].flag);
dh=line[i+1].h-line[i].h;
res+=dh*T[1].len;
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",q++,res);
}
return 0;
}

HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)的更多相关文章

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

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

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

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

  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. POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]

    题意:求矩形面积并 分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化! 把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区 ...

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

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

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

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

  8. hdu 4419 线段树 扫描线 离散化 矩形面积

    //离散化 + 扫描线 + 线段树 //这个线段树跟平常不太一样的地方在于记录了区间两个信息,len[i]表示颜色为i的被覆盖的长度为len[i], num[i]表示颜色i 『完全』覆盖了该区间几层. ...

  9. POJ 1177 Picture(线段树 扫描线 离散化 求矩形并面积)

    题目原网址:http://poj.org/problem?id=1177 题目中文翻译: 解题思路: 总体思路: 1.沿X轴离散化建树 2.按Y值从小到大排序平行与X轴的边,然后顺序处理 如果遇到矩形 ...

随机推荐

  1. Android procrank , showmap 内存分析

    (一)DDMS 的Heap Dump 1) Data Object:java object. 2) Class Object:object of type Class, e.g. what you'd ...

  2. struts1老古董配置

    <!--Struts1 struts-config.xml Demo --><?xml version="1.0" encoding="UTF-8&qu ...

  3. MVC准备前基础知识

    一.自动属性C#自动属性可以避免原来这样我们手工声明一个私有成员变量以及编写get/set逻辑public class Product{ public int Id { get; set; } pub ...

  4. C语言,输入一个正整数,按由大到小的顺序输出它的所有质数的因子(如180=5*3*3*2*2)

    #include <iostream> using namespace std; int main() { long num; while(cin >> num){ ){ co ...

  5. OneApm

    cloudinsight-java-sdk https://github.com/cloudinsight

  6. VMware Workstation卸载清理批处理命令

    echo offclsecho "flag">>%windir%\system32\test.logif not exist %windir%\system32\tes ...

  7. [转载]有了 malloc/free 为什么还要 new/delete ?

      malloc 与free 是C++/C 语言的标准库函数,new/delete 是C++的运算符.他们都可以用于申请动态内存和释放内存.      对于非内部数据类型的对象(如类对象)而言,光用m ...

  8. Xamarin.Android提示aapt退出,代码为255

    Xamarin.Android提示aapt退出,代码为255 错误信息:”aapt.exe”已退出,代码为255.出现这种问题,通常是由于该项目所使用Android SDK不完整.通过SDK Mana ...

  9. Hierarchy视图里的Transform和Camera组件

    Hierarchy视图里的Transform和Camera组件 在Hierarchy视图里,选中Camera,然后在Inspector视图里查看其各组件,如图1-8所示.对于Transform和Cam ...

  10. Android渗透测试Android渗透测试入门教程大学霸

    Android渗透测试Android渗透测试入门教程大学霸 第1章  Android渗透测试 Android是一种基于Linux的自由及开放源代码的操作系统,主要用于移动设备,如智能手机.平板等.目前 ...