扫描线算是线段树的一个比较特殊的用法,虽然NOIP不一定会考,但是学学还是有用的,况且也不是很难理解。

以前学过一点,不是很透,今天算是搞懂了。

就以这道题为例吧:嘟嘟嘟

题目的意思是在一个二维坐标系中给了很多矩形,然后求这些矩形的总覆盖面积,也就是面积并。

我就不讲暴力,直接切入正题吧。

扫描线,听这个名字就可以想象一下,现在有这么多重叠的矩形,然后有一个线从下往上扫,那么每一时刻这条线上被覆盖的长度之和,就是我们要求的答案。

那么首先可以想到,要把给定的矩形都离线下来,拆成上下来个面,并标记这个矩形从哪开始,从哪结束,最后按x(或y)排好序。

上面的可以算作预处理,接下来才是重点:怎么用线段树维护这个扫描线的覆盖问题?

首先要清楚的是,这并不是单纯的区间覆盖,因为区间覆盖的清空是把这个区间都清零,但是在对于扫线上的一段区间的清空,实际上只是清空了这一层,而他下面那一层应该还保持原样。这该怎么实现呢? 

首先需要一个cov标记,表示这个区间被覆盖了几层,那么一个矩形的开始就是多覆盖一层,结束就是减去一层。由此可知,如果cov > 1的话,那么这个区间就全被覆盖了,sum就等于区间长度;那么cov = 0呢?说明这个区间只有一部分被覆盖,sum[now] = sum[now <<1] +sum[now <<1 | 1]。这是为什么就等于左右子区间的和呢?想一下,我们更新的时候,要是更新区间和当前区间一样的话,就停止了,那么他的子区间还是保持了原来的情况。因此我们掀开了这一层,露出来的就是他的子区间那没有被完全覆盖的情况。因此sum[now] = sum[now << 1] +sum[now <<1 | 1].

还有一点,那就是cov永远不会小于0,因为cov--的条件是有一个矩形结束了,那有结束必定有开始,所以一定是先加后减。但有人又会问,如果是别的矩形改变了这个区间的cov值呢?那也同理,也是先加后减。所以cov永远是大于0的。

pushup也一样,cov大于0,则sum就是区间长度,否则是左右子区间的和。

(懒得画图……)

 #include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-;
const int maxn = 5e4 + ;
inline ll read()
{
ll ans = ;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) {last = ch; ch = getchar();}
while(isdigit(ch)) {ans = ans * + ch - ''; ch = getchar();}
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < ) x = -x, putchar('-');
if(x >= ) write(x / );
putchar(x % + '');
} int xl, yl, xr, yr, cnt = ;
struct Node
{
int L, R, h, flg;
bool operator < (const Node &oth)const
{
return h < oth.h;
}
}a[maxn << ]; int l[maxn << ], r[maxn << ], sum[maxn << ], cov[maxn << ];
void build(int L, int R, int now)
{
sum[now] = cov[now] = ;
l[now] = L; r[now] = R;
if(L == R) return;
int mid = (L + R) >> ;
build(L, mid, now << );
build(mid + , R, now << | );
}
void update(int L, int R, int flg, int now)
{
if(L == l[now] && R == r[now])
{
cov[now] += flg;
if(cov[now]) sum[now] = R - L + ;
else
{
if(L == R) sum[now] = ; //别忘判断叶子节点
else sum[now] = sum[now << ] + sum[now << | ];
}
return;
}
int mid = (l[now] + r[now]) >> ;
if(R <= mid) update(L, R, flg, now << );
else if(L > mid) update(L, R, flg, now << | );
else update(L, mid, flg, now << ), update(mid + , R, flg, now << | );
if(cov[now]) sum[now] = r[now] - l[now] + ;
else sum[now] = sum[now << ] + sum[now << | ];
} int solve()
{
build(, maxn - , );
ll ans = ;
sort(a + , a + cnt + );
for(int i = ; i <= cnt; ++i)
{
update(a[i].L, a[i].R, a[i].flg, );
ans += sum[] * (a[i + ].h - a[i].h);
}
return ans;
} int main()
{
while()
{
cnt = ;
bool flg = ;
while()
{
xl = read() + ; yl = read() + ; xr = read(); yr = read() + ;
if(!xl && !flg) return ;
else if(!xl) break;
else
{
a[++cnt] = (Node){xl, xr, yl, };
a[++cnt] = (Node){xl, xr, yr, -};
flg = ;
}
}
write(solve()); enter;
}
return ;
}

线段树扫描线总结(POJ 1389)的更多相关文章

  1. 线段树 扫描线 L - Atlantis HDU - 1542 M - City Horizon POJ - 3277 N - Paint the Wall HDU - 1543

    学习博客推荐——线段树+扫描线(有关扫描线的理解) 我觉得要注意的几点 1 我的模板线段树的叶子节点存的都是 x[L]~x[L+1] 2 如果没有必要这个lazy 标志是可以不下传的 也就省了一个pu ...

  2. 【POJ-2482】Stars in your window 线段树 + 扫描线

    Stars in Your Window Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11706   Accepted:  ...

  3. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  4. Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)

    题目链接:http://codeforces.com/contest/522/problem/D 题目大意:  给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...

  5. HDU 4419 Colourful Rectangle --离散化+线段树扫描线

    题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...

  6. BZOJ-3228 棋盘控制 线段树+扫描线+鬼畜毒瘤

    3228: [Sdoi2008]棋盘控制 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 23 Solved: 9 [Submit][Status][D ...

  7. BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞

    看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...

  8. hdu 5091(线段树+扫描线)

    上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...

  9. POJ1151+线段树+扫描线

    /* 线段树+扫描线+离散化 求多个矩形的面积 */ #include<stdio.h> #include<string.h> #include<stdlib.h> ...

  10. POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]

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

随机推荐

  1. qs.parse()、qs.stringify()、JSON.parse()、JSON.stringify()使用方法

    一.JSON.parse(用于从一个字符串中解析出json 对象)ps:单引号写在{}外,每个属性都必须双引号,否则会抛出异常 let str = '[{"field":" ...

  2. 部署项目到远程tomcat的413 Request Entity Too Large报错处理

    当项目jar包过多时,部署项目会报错而错误原因很清楚了,文件太大了. 因为用了nginx代理,而nginx默认文件大小有限,所以需要设置nginx上传文件大小限制 client_max_body_si ...

  3. IntelliJ IDEA 使用 LiveEdit 插件实现实时可视化前端开发

    之前因为公司很多都是C#后台项目,所以一直用的Visual Studio开发.而在VS里会自带实时刷新功能,即:在IDE中修改的CSS代码会同步反映在页面上,而不用我们手动F5刷新. 先在因为在考虑做 ...

  4. URAL 1252 ——Sorting the Tombstones——————【gcd的应用】

    Sorting the Tombstones Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I ...

  5. 深入理解JavaScript系列(5):强大的原型和原型链

    前言 JavaScript 不包含传统的类继承模型,而是使用 prototypal 原型模型. 虽然这经常被当作是 JavaScript 的缺点被提及,其实基于原型的继承模型比传统的类继承还要强大.实 ...

  6. Python实现抓取CSDN博客首页文章列表

    1.使用工具: Python3.5 BeautifulSoup 2.抓取网站: csdn首页文章列表 http://blog.csdn.net/ 3.分析网站文章列表代码: 4.实现抓取代码: __a ...

  7. IIS发布常见错误-HTTP 错误 404.0 - Not-Found

    错误信息:HTTP 错误 404.0 - Not-Found 错误代码:0x80070002 原 因:IIS配置错误. 解决方法:我配置IIS时漏掉了下面几项,一定要记得勾选.

  8. attribute和property的区别

    DOM元素的attribute和property很容易混倄在一起,分不清楚,两者是不同的东西,但是两者又联系紧密.很多新手朋友,也包括以前的我,经常会搞不清楚. attribute翻译成中文术语为“特 ...

  9. PAT 1021 Deepest Root

    #include <cstdio> #include <cstdlib> #include <vector> using namespace std; class ...

  10. SQL:exec sp_executesql 用法

    --這種是無效的過程 declare @sql nvarchar(500), @where nvarchar(500),@i nvarchar(64),@p nvarchar(50),@id int ...