POJ 1151 Atlantis(扫描线)

Posted lipeiyi520

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1151 Atlantis(扫描线)相关的知识,希望对你有一定的参考价值。

题目原链接:http://poj.org/problem?id=1151

题目中文翻译:

POJ 1151 Atlantis

Time Limit: 1000MS

 

Memory Limit: 10000K

Total Submissions: 25769

 

Accepted: 9477

Description

有几个古希腊文本包含传说中的亚特兰蒂斯岛的描述。 其中一些文本甚至包括岛屿部分地图。 但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。 您的朋友Bill必须知道地图的总面积。 你(不明智地)自告奋勇写了一个计算这个数量的程序。

Input

输入包含几个测试用例。 每个测试用例都以一行包含一个整数n(1 <= n <= 100)开始,指示可用的地图。以下n行描述了每个地图。 这些行中的每一行包含四个数字x1; y1; x2; y2(0 <= x1 <x2 <= 100000; 0 <= y1 <y2 <= 100000),不一定是整数。 值(x1; y1)和(x2; y2)是地图左上角和右下角的坐标。

输入文件以包含单个0的行作为终止。不处理它。

Output

对于每个测试用例,您的程序应输出一个部分。 每个部分的第一行必须是“Test case #k”,其中k是测试用例的编号(从1开始)。 第二个必须是“Total explored area:a”,其中a是总探索区域(即此测试用例中所有矩形的覆盖区域),精确到小数点后两位数。

在每个测试用例后输出一个空行。

Sample Input

2

10 10 20 20

15 15 25 25.5

0

Sample Output

Test case #1

Total explored area: 180.00

解题思路:

本人太菜,无法描述,请看大佬详解:AKIOI

AC代码:

(由此大佬博客借鉴而来:code)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 struct kkk{//线段树 
 8     int l,r;//线段树的左右整点
 9     int c;//c用来记录重叠情况
10     double cnt,lf,rf;//cnt用来计算实在的长度,lf,rf分别是对应的左右真实的浮点数端点 
11 }s[603];
12 
13 struct k2{
14     double x,y1,y2;
15     int f;
16 }l[603]; 
17 //把一段段平行于y轴的线段表示成数组 ,
18 //x是线段的x坐标,y1,y2线段对应的下端点和上端点的坐标 
19 //一个矩形 ,左边的那条边f为1,右边的为-1,
20 //用来记录重叠情况,可以根据这个来计算,kkk节点中的c 
21 
22 double y[201];//记录y坐标的数组
23 
24 bool cmp(k2 a,k2 b) {
25     return a.x < b.x;
26 }
27 
28 void build(int t,int l,int r) {
29     s[t].l = l;s[t].r = r;
30     s[t].cnt = s[t].c = 0;
31     s[t].lf = y[l];
32     s[t].rf = y[r];
33     if(l + 1 == r) return ;
34     int mid = (l + r) >> 1;
35     build(t << 1,l,mid);
36     build(t << 1 | 1,mid,r);
37 }
38 
39 void calen(int t) {//计算长度
40     if(s[t].c > 0) {//不是最后一条出边 
41         s[t].cnt = s[t].rf - s[t].lf;
42         return ;
43     }
44     if(s[t].l + 1 == s[t].r) s[t].cnt = 0;//因为用左闭右开数组,所以长度为0,就相当于一个点 
45     else s[t].cnt = s[t<<1].cnt + s[t<<1|1].cnt;//否则用儿子计算自己 
46 }
47 
48 void update(int t,k2 e) {//加入线段e,后更新线段树
49     if(e.y1 == s[t].lf && e.y2 == s[t].rf) {//如果正好找到区间 
50         s[t].c += e.f; 
51         calen(t);
52         return ;
53     }
54     if(e.y2 <= s[t<<1].rf) update(t<<1,e);//下传左儿子 
55     else if(e.y1 >= s[t<<1|1].lf) update(t<<1|1,e);//下传右儿子 
56     else {//左右儿子都下传 
57         k2 tmp = e;
58         tmp.y2 = s[t<<1].rf;
59         update(t<<1,tmp);
60         tmp = e;
61         tmp.y1 = s[t<<1|1].lf;
62         update(t<<1|1,tmp);
63     }
64     calen(t);
65 }
66 
67 int main() {
68     int i,n,t,aa = 0;
69     double x1,y1,x2,y2;
70     while(scanf("%d",&n),n) {
71         aa++;
72         t = 1;
73         for(int i = 1;i <= n; i++) {
74             scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
75             l[t].x = x1;
76             l[t].y1 = y1;
77             l[t].y2 = y2;
78             l[t].f = 1;
79             y[t++] = y1;
80             l[t].x = x2;
81             l[t].y1 = y1;
82             l[t].y2 = y2;
83             l[t].f = -1;
84             y[t++] = y2;
85         }
86         sort(l+1,l+t,cmp);
87         sort(y+1,y+t);
88         build(1,1,t-1);//建树 
89         update(1,l[1]);//下传lazy标记 
90         double res = 0;
91         for(int i = 2;i < t; i++) {
92             res += s[1].cnt * (l[i].x - l[i-1].x);
93             update(1,l[i]);
94         }
95         printf("Test case #%d\\nTotal explored area: %.2f\\n\\n",aa,res);
96     }
97 }

 

以上是关于POJ 1151 Atlantis(扫描线)的主要内容,如果未能解决你的问题,请参考以下文章

POJ1151 Atlantis 扫描线

poj1151 Atlantis (线段树+扫描线+离散化)

POJ1151Atlantis(线段树,扫描线)

POJ 1151Atlantis

POJ 1151 Atlantis(线段树 + 扫描线)

poj1151 Atlantis——扫描线+线段树