扫描线算是线段树的一个比较特殊的用法,虽然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. spark第七篇:Spark SQL, DataFrame and Dataset Guide

    预览 Spark SQL是用来处理结构化数据的Spark模块.有几种与Spark SQL进行交互的方式,包括SQL和Dataset API. 本指南中的所有例子都可以在spark-shell,pysp ...

  2. Gradle发布项目到 maven(1)

    常见的 Maven 仓库 JCenter.MavenCenter.JitPack epositories { google() // google 仓库 jcenter() // JCenter 仓库 ...

  3. 基于云计算的IaaS、PaaS、SaaS三种服务模式的区别

    Infrastructure-as-a-Service(IaaS) - 基础即设施服务 基础设施主要包括网络系统(networking).存储设备(storage).服务器(servers).虚拟化技 ...

  4. Rancher2.0 外置存储卷

    一,环境准备 01,基础环境 一台rancher集群 服务器搭建参考原先文章 >>飞机直达 一台nfs服务器 02,nfs服务器搭建 rpm -qa rpcbind|grep rpcbin ...

  5. es6 vs commonjs

    'use strict' export function showMe() { alert("es6"); }; class logging { constructor() { a ...

  6. 【Tensorflow】 Object_detection之liunx服务器安装部署步骤记录

    环境:centos7+anaconda python3.6 步骤: 1.下载Models cd 到预存放目录下,执行: git clone https://github.com/tensorflow/ ...

  7. 牛客网Java刷题知识点之数组、链表、哈希表、 红黑二叉树

    不多说,直接上干货! 首先来说一个非常形象的例子,来说明下数组和链表. 上体育课的时候,老师说:你们站一队,每个人记住自己是第几个,我喊到几,那个人就举手,这就是数组. 老师说,你们每个人记住自己前面 ...

  8. Linux软件安装的补充

    1 使用yum 命令查看软件提供的版本 yum list mysql* 然后比如说都需要安装我们就可以执行命令: yum install mysql* 然后就会安装所有的.会显示所有需要安装的包,和需 ...

  9. Android中dip, dp, px,pt, sp之间的区别:

    Android中dip.dp.sp.pt和px的区别   1.概述 过去,程序员通常以像素为单位设计计算机用户界面.例如:图片大小为80×32像素.这样处理的问题在于,如果在一个每英寸点数(dpi)更 ...

  10. nyoj 409——郁闷的C小加(三)——————【中缀式化前缀后缀并求值】

    郁闷的C小加(三) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 聪明的你帮助C小加解决了中缀表达式到后缀表达式的转换(详情请参考“郁闷的C小加(一)”),C小加很 ...