POJ 1151:Atlantis 线段树+扫描线
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 19374 | Accepted: 7358 |
Description
total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
Input
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
(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
题意是给出诸多矩形的左下角坐标和右上角坐标,问这些矩形一共覆盖的面积。
看了真的是很久很久,终于把这道题的代码搞懂了,趁着对这道题有很多感觉,赶紧记下来。也通过这些题,发现线段树的应用范围真的是广。
实际上就是对每一段的x,求其y的长度,相乘就是对应的面积。最后把所有的面积加起来就是总面积。为了防止可能会发生重复加的面积,使用了线段树的结构。
首先是离散化,把y坐标上的浮点数 变成1 2 3 ---,然后使用对每一条边使用二分查找。
然后线段树中的每一个节点就代表了相应段的y的长度,和之前的线段树一样,线段树的思想就是我要使用哪一段的长度,我再去计算它更新它,这里面的len就代表了这个含义。
然后就是cover,cover就是只有为0的时候去更新它,因为不是0的时候代表着它依然被某个矩形覆盖着,所以不能更新成子节点的长度之和。
dele就是将原来的长度划出掉,cover--,判断为0就更新该点的len。
写到哪里算哪里,看着这段代码,觉得真的很奇妙。
代码:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
using namespace std; double y[210]; struct li
{
double x,y1,y2;
bool bleft;
}lines[210]; struct no
{
int L,R;
double len;
int cover; }tree[10000]; bool operator < (const li &n1,const li &n2)
{
return n1.x<n2.x;
} template <class F,class T>
F bin_search(F s,F e,T val)
{
F L = s;
F R = e-1; while(L<=R)
{
F mid = L + (R-L)/2;
if(!(*mid<val || val < *mid))
{
return mid;
}
else if(val < *mid)
{
R = mid -1;
}
else
{
L= mid + 1;
}
}
} void buildtree(int root,int L,int R)
{
tree[root].L=L;
tree[root].R=R; tree[root].len=0;
tree[root].cover=0; if(L!=R)
{
int mid = (L+R)/2;
buildtree(root*2+1,L,mid);
buildtree(root*2+2,mid+1,R);
}
} void inse(int root,int L,int R)
{
if(tree[root].L==L&&tree[root].R==R)
{
tree[root].cover++;
tree[root].len= y[R+1] - y[L];
return;
}
int mid = (tree[root].L + tree[root].R)/2; if(R<=mid)
{
inse(root*2+1,L,R);
}
else if(L>=mid+1)
{
inse(root*2+2,L,R);
}
else
{
inse(root*2+1,L,mid);
inse(root*2+2,mid+1,R);
}
if(tree[root].cover==0)
{
tree[root].len = tree[root*2+1].len + tree[root*2+2].len;
}
} void dele(int root,int L,int R)
{
if(tree[root].L == L && tree[root].R == R)
{
tree[root].cover--;
if(tree[root].cover==0)
{
if(tree[root].L == tree[root].R)
{
tree[root].len=0;
}
else
{
tree[root].len = tree[root*2+1].len + tree[root*2+2].len;
}
}
return;
} int mid = (tree[root].L + tree[root].R)/2;
if(R<=mid)
{
dele(root*2+1,L,R);
}
else if(L>=mid+1)
{
dele(root*2+2,L,R);
}
else
{
dele(root*2+1,L,mid);
dele(root*2+2,mid+1,R);
} if(tree[root].cover==0)
{
tree[root].len = tree[root*2+1].len + tree[root*2+2].len;
}
}
int n; int main()
{
int i,yc,lc,t;
double x1,x2,y1,y2;
t=0;
while(scanf("%d",&n)!=EOF)
{
if(n==0)
break;
t++;
yc=0;
lc=0;
for(i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
y[yc++]=y1;
y[yc++]=y2; lines[lc].x=x1;
lines[lc].y1=y1;
lines[lc].y2=y2;
lines[lc].bleft=true;
lc++; lines[lc].x=x2;
lines[lc].y1=y1;
lines[lc].y2=y2;
lines[lc].bleft=false;
lc++;
}
sort(lines,lines+lc);
sort(y,y+yc);
yc=unique(y,y+yc)-y; buildtree(0,0,yc-1-1);
double Area=0; for(i=0;i<lc-1;i++)
{
int L=bin_search(y,y+yc,lines[i].y1)-y;
int R=bin_search(y,y+yc,lines[i].y2)-y; if(lines[i].bleft)
{
inse(0,L,R-1);
}
else
{
dele(0,L,R-1);
}
Area += tree[0].len*(lines[i+1].x-lines[i].x);
}
printf("Test case #%d\n",t);
printf("Total explored area: %.2lf\n",Area);
printf("\n");
} //system("pause");
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
POJ 1151:Atlantis 线段树+扫描线的更多相关文章
- POJ 1151 - Atlantis 线段树+扫描线..
离散化: 将所有的x轴坐标存在一个数组里..排序.当进入一条线段时..通过二分的方式确定其左右点对应的离散值... 扫描线..可以看成一根平行于x轴的直线..至y=0开始往上扫..直到扫出最后一条平行 ...
- hdu 1542&&poj 1151 Atlantis[线段树+扫描线求矩形面积的并]
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- POJ 1151 Atlantis 线段树求矩形面积并 方法详解
第一次做线段树扫描法的题,网搜各种讲解,发现大多数都讲得太过简洁,不是太容易理解.所以自己打算写一个详细的.看完必会o(∩_∩)o 顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中, ...
- POJ 1151 Atlantis 线段树+离散化+扫描线
这次是求矩形面积并 /* Problem: 1151 User: 96655 Memory: 716K Time: 0MS Language: G++ Result: Accepted */ #inc ...
- hdu1542 Atlantis 线段树--扫描线求面积并
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some ...
- 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 ...
- 【42.49%】【hdu 1542】Atlantis(线段树扫描线简析)
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...
- POJ1151 Atlantis 线段树扫描线
扫描线终于看懂了...咕咕了快三个月$qwq$ 对于所有的横线按纵坐标排序,矩阵靠下的线权值设为$1$,靠上的线权值设为$-1$,然后执行线段树区间加减,每次的贡献就是有效宽度乘上两次计算时的纵坐标之 ...
随机推荐
- Java-用星号打印菱形
打印如图所示菱形9行9列(提示可以将菱形分成上下两个三角形,分析每行空格数和星号个数的关系) 代码如下: package com.homework.lhh; public class Ex20 { p ...
- idea右键新建选项没有类和包的创建方式
Intelidea创建好项目之后,右键新建Java class的时候发现没有改选项,只有以下几个选项 把sec目录设为源码目录,首先打开Project Structure
- 解决在高分屏下开发winform界面变形
Form.AutoScaleMode = AutoScaleMode.None; 需要在超大屏下显示的时候,再考虑 AutoScaleMode.Font; AutoScaleMode.Dpi;
- Numpy 为运算
Numpy “bitwise_” 开头的函数是位运算函数: Numpy 位运算包括以下几个函数: 函数 描述 bitwise_and 对数组元素执行位与操作 bitwise_or 对数组元素执行 ...
- 【转】彻底搞透Netty框架
本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希望给大家在实际开发实践.学习开源项目方面提供参考. Netty 是一个异步事件驱动的网络应用程序 ...
- Laradock 开放 workspace 端口
1.在 laradock/workspace/Dockerfile 文件的最后添加一行,申明开放端口: EXPOSE 1215; 2.在 laradock/docker-compose ...
- P1001 A+B Format
转跳点:
- re模块补充 configparse模块
import rere.findall("(?:abc)+","abcabcabc")--->['abcabcabc'] import configpar ...
- 5.6 Nginx Rewrite模块配置
- 对于文章的字母、单词、短语,(无用词表)的检索Java代码实现
日期:2019.5.9 博客期:073 星期四 今天软件工程课上,又做了测试,老师说我们的速度太慢了,实际上我也觉得自己很慢.老师说了这是我们的上一届的大二上半学期学习中的速度,所以呢?意思就是说我们 ...