扫描线的基础概念可以看这几篇文章

http://blog.csdn.net/xingyeyongheng/article/details/8927732

http://www.cnblogs.com/scau20110726/archive/2013/03/21/2972808.html

在这里讲一下应用

1.求矩形的面积并

以hdu 1542为例:

给出n个矩阵的对角坐标,求矩阵的面积并。

这里需要注意这么几点:

  • 离散化

因为数据跨度很大,所以肯定要将数据离散化,保存在hash数组中。但要小心离散化本身的坑。

离散化的坑,就是在表示线段树时,我们会把1-4划分为1-2和3-4,如果覆盖1-2和3-4就等同于把整个线段覆盖了,但其实不对,因为2和3中间也是有值的。

下面这题也遇到这个坑,解决方法是:在update时读入r-1,计算时使用r+1

  • 水平扫描的话,hash的是y坐标,反之亦然
  • hash最好要去重
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <queue>
#include <cctype>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <sstream>
using namespace std; #define mem(a,b) memset(a,b,sizeof(a))
#define pf printf
#define sf scanf
#define spf sprintf
#define pb push_back
#define debug printf("!\n")
#define MAXN 200+5
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#define LL long long
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pqueue priority_queue
#define INF 0x3f3f3f3f #define ls (rt<<1)
#define rs (rt<<1|1) int n,m; double hh[MAXN],col[MAXN<<],len[MAXN<<]; struct node
{
double l,r,x,c;
node(){}
node(double a,double b,double c,double d):l(a),r(b),x(c),c(d){}
bool operator < (const node &b) const
{
return x<b.x;
}
}a[MAXN]; void PushUp(int rt,int l,int r)
{
if(col[rt])
{
len[rt] = hh[r+] - hh[l];
}
else if(l==r) len[rt] = ;
else
{
len[rt] = len[ls]+len[rs];
}
} void update(int val,int L,int R,int l,int r,int rt)
{
if(L<=l && r<=R)
{
col[rt] += val;
PushUp(rt,l,r);
return;
}
int mid = (l+r)>>;
if(L <= mid) update(val,L,R,l,mid,ls);
if(R > mid) update(val,L,R,mid+,r,rs);
PushUp(rt,l,r);
} int main()
{
int i,j,k,t,kase=;
while(~sf("%d",&n) && n)
{
int v=;
double sum = ;
for(i=;i<n;i++)
{
double x1,y1,x2,y2;
sf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
hh[v] = y1;
a[v++] = node(y1,y2,x1,);
hh[v] = y2;
a[v++] = node(y1,y2,x2,-);
}
sort(hh,hh+v);
sort(a,a+v);
int d = ;
for(i=;i<v;i++)
{
if(hh[i]!=hh[i-]) hh[d++] = hh[i];
}
mem(len,);
mem(col,);
for(i=;i<v-;i++)
{
int l = lower_bound(hh,hh+d,a[i].l)-hh;
int r = lower_bound(hh,hh+d,a[i].r)-hh-;
update(a[i].c,l,r,,d-,);
sum+=len[]*(a[i+].x-a[i].x);
//pf("%lf %lf\n",sum,len[1]);
}
pf("Test case #%d\nTotal explored area: %.2lf\n\n",kase++,sum);
} return ;
}

2.求矩形周长并

以hdu 1828为例:

http://blog.csdn.net/xingyeyongheng/article/details/8931410

http://www.cnblogs.com/scau20110726/archive/2013/04/13/3018687.html

http://www.cnblogs.com/scau20110726/archive/2013/04/13/3018702.html

三篇很不错的文章,基础概念可以看这几个

从面积变成了周长,方法其实是差不多的。解决这个问题有两种思路:

  1. 对横线,竖线分别做一次处理。分别求出有效覆盖长度,两者之和就是结果。

    • 把矩形分成横线和竖线去处理,可知是完全相同的操作,我们来讲下怎么算出横线部分,竖线部分就是照搬即可。

      将横线保存在一个表中,按横线所处的竖直位置排序(升序),另外每条横线带一个标记值,原矩形的下线为1,上线为-1(对应过去就是插入线段和删除线段)

      从低到高扫描横线,没扫到一条横线就能计算出一部分横线值。计算方法是算出现在总区间的被覆盖的长度,然后求出与上一次的总区间的覆盖长度的差(即相减求绝对值),因为每次添加了一条线段,如果没有没有使总区间覆盖长度发生变化,说明这条线段其实在多边形的内部,被覆盖掉了,不能计算,只要能引起总区间长度发生变化的,说明该线段不被覆盖不被包含,要计算

      而竖线部分的做法是一样的,把竖线保存在一个表中,按水平位置排序(升序),每条横线带一个标记值,原矩形的左线为1,右线为-1,然后同样地操作

  2. 通过记录覆盖的左右端点,以及数量信息,判断是否覆盖,扫描一次的同时求出两线长度。
    • 前面的工作是相同的,把横线保存在一个表中,按竖直位置排序,然后从下往上扫描所有横线,在这个方法中,每次扫描一条横线,都能计算出两不部分值,一部分是横线的,一部分是竖线的

      而计算横线部分的方法和第一种方法是一样的,即求出【现在这次总区间被覆盖的长度和上一次总区间被覆盖的长度的差的绝对值】,另外怎么算竖线部分呢?首先我们要知道添加了这条横线后会有多少条竖线,答案是2*num,所以为什么要记录num呢,因为总区间被num条线段覆盖,那么必定有2*num的端点,这些端点其实就是连着竖线,那么这些竖线的长度是多少呢?

      就是【下一条横线的高度-现在这条横线的高度】,只要把这个高度乘上2*num即可

我采用的是第二种方法,这里不需要离散化,代码如下:

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <queue>
#include <cctype>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <sstream>
using namespace std; #define mem(a,b) memset(a,b,sizeof(a))
#define pf printf
#define sf scanf
#define spf sprintf
#define pb push_back
#define debug printf("!\n")
#define MAXN 20000+5
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#define LL long long
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pqueue priority_queue
#define INF 0x3f3f3f3f #define ls (rt<<1)
#define rs (rt<<1|1) int n,m; int col[MAXN<<],len[MAXN<<],lseg[MAXN<<],rseg[MAXN<<],segnum[MAXN<<]; struct node
{
int l,r,x,c;
node(){}
node(int a,int b,int c,int d):l(a),r(b),x(c),c(d){}
bool operator < (const node &b) const
{
return x<b.x || x==b.x && c>b.c;
}
}a[MAXN]; void PushUp(int rt,int l,int r)
{
if(col[rt])
{
len[rt] = r-l+;
segnum[rt]=;
lseg[rt] = rseg[rt] = ;
}
else if(l==r) len[rt] = segnum[rt] = lseg[rt] = rseg[rt] = ;
else
{
len[rt] = len[ls]+len[rs];
segnum[rt] = segnum[ls]+segnum[rs];
lseg[rt] = lseg[ls];
rseg[rt] = rseg[rs];
if(lseg[rs] && rseg[ls]) segnum[rt]-=;
}
} void update(int val,int L,int R,int l,int r,int rt)
{
if(L<=l && r<=R)
{
col[rt] += val;
PushUp(rt,l,r);
return;
}
int mid = (l+r)>>;
if(L <= mid) update(val,L,R,l,mid,ls);
if(R > mid) update(val,L,R,mid+,r,rs);
PushUp(rt,l,r);
} int main()
{
int i,j,k,t,kase=;
while(~sf("%d",&n) && n)
{
int left = ,right = -,v=,ans=,last=;
mem(len,);
mem(col,);
mem(segnum,);
mem(lseg,);
mem(rseg,);
for(i=;i<n;i++)
{
int x1,y1,x2,y2;
sf("%d%d%d%d",&x1,&y1,&x2,&y2);
a[v++] = node(y1,y2,x1,);
a[v++] = node(y1,y2,x2,-);
left = min(left,y1);
right = max(right,y2);
}
//pf("%d %d\n",left,right);
sort(a,a+v);
for(i=;i<v;i++)
{
if(a[i].l < a[i].r) update(a[i].c,a[i].l,a[i].r-,left,right,);
ans+= segnum[]*(a[i+].x-a[i].x);
ans+= abs(len[]-last);
last = len[];
}
pf("%d\n",ans);
} return ;
}

ACM-线段树扫描线总结的更多相关文章

  1. 2018牛客网暑假ACM多校训练赛(第四场)E Skyline 线段树 扫描线

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round4-E.html 题目传送门 - https://www.no ...

  2. hdu 4052 线段树扫描线、奇特处理

    Adding New Machine Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  3. HDU 1542 - Atlantis - [线段树+扫描线]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Time Limit: 2000/1000 MS (Java/Others) Memory Li ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. linux操作之文本编辑器

    1.文本编辑器的作用 编辑和修改系统中的那些以文本形式存在的文件(特别是各种配置文件),也可以用于 编写程序代码 2.linux下的常见编辑器 nano.Emacs.gedit.vim等 3.vim三 ...

  2. 流水的算法,铁打的损失函数/MLE

    机器学习算法可以说是不少的,如果死记硬背的话,只能当时记得推导过程和步骤,过一段时间就又想不起来了,只能依稀记得一些影子.所以,应该找到算法的一些通用的方法来理解算法的思路以及推导过程. 我认为,最大 ...

  3. The server of Apache (四)——配置防盗链和隐藏版本信息

    一.防盗链 防盗链就是防止别人的网站代码里面盗用我们服务器的图片.文件.视频等相关资源,比如我们的网页的图片有链接,别人把链接复制粘贴到他们的服务器页面里,图片不在他们自己的网站里,每次打开他们的网站 ...

  4. springcloud微服务总结三 服务客户端

    一 springcloud服务理解: dubbo中服务注册和调用都是都过注解来进行的,dubbo中在service层中调用服务是通过将@service注解改变为dubbo代码架包中的service注解 ...

  5. jquery查找子元素和兄弟元素

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  6. flask-login

    创建扩展对象实例 from flask_login import LoginManager login_manager = LoginManager() login_manager.login_vie ...

  7. mysql 表的分区

    如何判断当前MySQL是否支持分区 命令:show variables like '%partition%' 运行结果: mysql> show variables like '%partiti ...

  8. LeetCode231.2的幂

    231.2的幂 描述 给定一个整数,编写一个函数来判断它是否是 2 的幂次方. 示例 示例 1: 输入: 1 输出: true 解释: 2^0 = 1 示例 2: 输入: 16 输出: true 解释 ...

  9. 64位的notepad++没有插件管理

    下载的64位的notepad++没有插件管理:需要自己下载这个插件: - plugin manager的下载地址为:https://github.com/bruderstein/nppPluginMa ...

  10. HDU - 1588 矩阵前缀和

    题意:给定\(k,b,n,m\),求\(\sum_{i=0}^{n-1}f(g(i))\) 其中\(f(i)=f(i-1)+f(i-2),f(1)=1,f(0)=0\),\(g(i)=k*i+b\) ...