扫描线 亚特兰蒂斯

2024-05-11 00:58
文章标签 扫描线 亚特兰蒂斯

本文主要是介绍扫描线 亚特兰蒂斯,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:247. 亚特兰蒂斯

算法分析

只说细节。

这道题目不是特别严格的线段树,因为线段树维护的信息具有区间可合并性,这道题目想了很久想不出可以区间直接合并的信息。我们在这里维护的是离散化后表示小段的数组,设为 a [ ] a[] a[]吧,对于一个边界的两个纵坐标,设为 y 1 y1 y1 y 2 y2 y2,离散化后的结果为 [ a l , a r ] [al,ar] [al,ar],这是点,如果要对应到小段,那么则是 [ a l , a r − 1 ] [al,ar-1] [al,ar1]

在每个区间结点上,设cnt表示该区间被完整扫过的次数,这里强调下,是完整扫过,那些子区间被扫过但本身没被完整扫过的不能累加。因此,满足不了区间可合并的特性。但是因为在树上,我们在更新线段树的时候,可以将结果从下往上累加,在每个结点上用len表示该区间被扫描线覆盖的长度。下面是重点:

当某个区间结点的cnt>0,则 t r [ p ] . l e n = v a l [ a r + 1 ] − v a l [ a l ] tr[p].len=val[ar+1] - val[al] tr[p].len=val[ar+1]val[al],因为线段树中维护的是小段,要计算的话,得转移到点上直接相减,所以右端点是 a r + 1 ar+1 ar+1

当某个区间结点的cnt=0,则它的len值是其左右儿子的len值之和。如果该点是叶结点,则len值重置为0。

if (tr[p].cnt)tr[p].len = val[ar+1] - val[al];else if (al != ar)tr[p].len = tr[2*p].len + tr[2*p+1].len;else tr[p].len = 0; 

该边界被扫描线覆盖的长度就是 t r [ 1 ] . l e n tr[1].len tr[1].len。不需要查询。事实上,这种做法下,查询了反而是错的。如果查询 [ a l , a r ] [al,ar] [al,ar],结果代表扫描线在区间 [ a l , a r + 1 ] [al,ar+1] [al,ar+1]被覆盖的长度,和要求不符,如果查询 [ 1 , c n t − 1 ] [1, cnt-1] [1,cnt1],有可能该结点的cnt为0,造成漏查。

根据以上分析,就无需下传标记了。

离散化的时候,除了要记录离散化后的整数对应原来的实数,还要记录原来的实数对应的整数。后者用map实现。也可以在lsh[]中用 l o w e r _ b o u n d lower\_bound lower_bound重新查询下位次。

map<double, int> lshval;
sort(lsh + 1, lsh + t + 1);
int cnt = unique(lsh + 1, lsh + t + 1) - lsh - 1;
for (int i = 1; i <= t; ++i)
{double tem = aa[i];a[i] = lower_bound(lsh + 1, lsh + cnt + 1, aa[i]) - lsh;val[a[i]] = tem;lshval[tem] = a[i];
}	

注意:离散化之前要对lsh数组排序。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
#define ll long long 
const int N = 1e4 + 10;
double aa[2*N], val[2*N], lsh[2*N];
int a[2*N];
int n;
map<double, int> lshval;
struct dot
{double x, y1, y2;int id;
}d[2*N];
struct SegmentTree
{double len;int cnt;
}tr[8*N];
double relf()
{double x = 0, y = 0.1, f = 1; char c = getchar();while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}while (c >= '0' && c <= '9'){x = x * 10 + c - '0'; c = getchar();}if (c == '.'){c = getchar();while (c >= '0' && c <= '9'){x += y * (c - '0'); y /= 10; c = getchar();} }return x * f; 
}
bool cmp(dot a, dot b)
{return a.x < b.x;
}
void szbuild(int p, int l, int r)
{tr[p].len = tr[p].cnt = 0;if (l == r) return;int mid = (l + r) >> 1;szbuild(2 * p, l, mid);szbuild(2 * p + 1, mid + 1, r);	
}
void szchange(int p, int al, int ar, int ql, int qr, int num)
{if (ql > ar || qr < al) return;  // 完全没交集,直接返回 if (ql <= al && ar <= qr){tr[p].cnt += num;if (tr[p].cnt)tr[p].len = val[ar+1] - val[al];else if (al != ar)tr[p].len = tr[2*p].len + tr[2*p+1].len;else tr[p].len = 0;  // 没有覆盖了,叶节点置为0 ,这点很重要  return;} int mid = (al + ar) >> 1;szchange(2 * p, al, mid, ql, qr, num);szchange(2 * p + 1, mid + 1, ar, ql, qr, num);if (tr[p].cnt)tr[p].len = val[ar+1] - val[al];else if (al != ar)tr[p].len = tr[2*p].len + tr[2*p+1].len;else tr[p].len = 0;  // 
}
int main()  // 标记不下传  
{int T = 0;while (1){++T;scanf("%d", &n);if (!n) break;int t = 0;double ax, ay, bx, by;for (int i = 1; i <= 2 * n; i += 2){ax = relf(); ay = relf(); bx = relf(); by = relf();d[i].x   = ax; d[i].y1   = ay;  d[i].y2   = by; d[i].id = 1;d[i+1].x = bx; d[i+1].y1 = ay;  d[i+1].y2 = by; d[i+1].id = -1;aa[++t] = ay; aa[++t] = by;}// 离散化  	memcpy(lsh, aa, sizeof(aa));sort(lsh + 1, lsh + t + 1);int cnt = unique(lsh + 1, lsh + t + 1) - lsh - 1;for (int i = 1; i <= t; ++i){double tem = aa[i];a[i] = lower_bound(lsh + 1, lsh + cnt + 1, aa[i]) - lsh;val[a[i]] = tem;lshval[tem] = a[i];}	// 建线段树维护小段,第i小段代表段val[i+1] - val[i]// 总共有cnt-1段  szbuild(1, 1, cnt - 1);// double ans = 0; sort(d + 1, d + 2 * n + 1, cmp);  // 按照x坐标排序  for (int i = 1; i <= 2 * n - 1; ++i){// [ql, qr]区间是要更新的区间  int ql = lshval[d[i].y1], qr = lshval[d[i].y2] - 1;	szchange(1, 1, cnt - 1, ql, qr, d[i].id);ans += (d[i+1].x - d[i].x) * tr[1].len;}printf("Test case #%d\n", T);printf("Total explored area: %.2lf\n\n", ans);}return 0;
}

反思与总结

  1. 码代码的时候要集中精力,第一遍的错误,很难发现纠正。尽量一遍过。

  2. 注意快读正负实型的写法。

这篇关于扫描线 亚特兰蒂斯的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/978061

相关文章

洛谷P5490扫描线

0是最小的数字,将一个线段看成一个区间,对于一个矩形,从下扫到上,入边为1,而出边为-1,意思是将这个区间上的所有点加1(区间修改).把线段表示为Line[i],其中记录了l,r,h,tag,左右端点,高度,入边还是出边(1或-1) 那么每次区间修改后不为0的区间它的值可能是1,2,3或者是其它数字,这不好统计,可以将它转化一下,0是不是表示没有被覆盖过的地方,我们只要统计0的个数然后用总长减去

Zxing扫描二维码精简(竖屏、拉伸处理、扫描框大小和扫描线移动、开灯)

自己在简版zxing的基础上美化了下,给大家分享下,直接扫描功能没问题。 就是从相册导入图片,解码一直不成功,导入图片解码 我引入了一个解码类  RGBLuminanceSource(百度网上二维码图片解码都是这个,我还把这个类编译了,导到core.jar包里面了), 好像是hity类型有问题,反正一直不成功。 有大神解决了,回复告诉我!谢谢! 分享 暂时没做效

扫描线Sweep Line算法总结

扫描线算法,推荐还是用标准的模板去写,treemap只适合于求最大的overlap个数的题目,其余的不能用treemap来解,所以推荐还是用event的思想去+1, -1然后排序扫描的方法可以用来解所有的题型; Number of Airplanes in the Sky 思路:经典扫描线算法:把interval起飞和降落做为event,全部打散,按照时间排列,同时时间相等的,按照降落在前面,起

矩形面积并、矩形面积交、矩形周长并(线段树、扫描线总结)

转自:http://blog.csdn.net/lwt36/article/details/48908031 HDU 1542 [POJ 1151] Atlantis (矩形面积并) 题意: 求N<=100个矩形的面积并 分析: 离散化: 这些技巧都是老生常谈的了, 不然浮点数怎么建树, 离散化 x 坐标就可以了扫描线: 首先把矩形按 y 轴分成两条边, 上边和下边,

【HDU1255】【线段树】【扫描线】【面积】

覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4417    Accepted Submission(s): 2180 Problem Description 给定平面上若干矩形,求出被这些矩形覆

poj2482--Stars in Your Window(扫描线)

题目链接:点击打开链接 链接题目大意:给出n个星星的坐标,每个星星有一个亮度,给出一个矩形的长和宽,问矩形能包括的星星的最大亮度和(不包括边框)。 假设每个星星都是矩形的最左下点,那么每一个星星都可以得到一个矩形,(x,y)->(x,y,x+w,y+h),这个矩形的两条高边的值也就是星星的亮度k和-k,对于不同的矩形来说,如果高线出现重合部分,那么也就是说这两个星是可以出现在同一个矩形中的,扫

HDU 1828 POJ 1177 Picture(线段树+扫描线+离散化)

HDU题目地址:HDU 1828  POJ题目地址:POJ 1177 这题是求周长并,我用的方法可能有点麻烦。。是先求横着的线,再求竖着的线。每次只要求出每次的总区间覆盖长度,然后每次累加这次的总区间覆盖与上次的总区间覆盖长度的差的绝对值。因为只有长度发生变化时,才会产生一段新的周长。 待会再试试只扫描一次的方法。此博客有待更新。 代码如下: #include <iostream>#

POJ 3277 City Horizon(线段树+扫描线+离散化)

题目地址:POJ 3277 水题。。稍微处理一下然后用求面积并的方法求即可。 代码如下: #include <iostream>#include <cstdio>#include <string>#include <cstring>#include <stdlib.h>#include <math.h>#include <ctype.h>#include <queue>#

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

题目地址:HDOJ地址:HDU 1542  POJ 地址:POJ 1151 第一发扫描线。。费了好大一番功夫。。构思用了半天。。写出来调试成功用了半天。。。真是弱渣。。 所谓扫描线就是从上往下或从下往上扫描,每到一个边,就进行增或删的处理。最后出来的值就是总的面积。对于求面积并的问题,可以参考这篇博客(博客地址),讲的不错。 具体实现过程是用lazy标记此时的边数量,如果大于0,说明这个地方

Atlantis 线段树扫描线--面积并

Atlantis Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 16755 Accepted: 6391 Description There are several ancient Greek texts that contain descript