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

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. python2和python3 分别连接MySQL的代码

    python2中的写法如下: #coding=utf-8 import MySQLdb try: conn = MySQLdb.connect(host='localhost', port=3306, ...

  2. python连接postgreSQL

    利用python(我用的是python2.7版本)连接postgresql数据库,这里使用psycopg2这个插件 官网下载psycopg2-2.5.1.tar.gz:http://initd.org ...

  3. c语言数据结构学习心得——树

    树 一对多的树型结构,有且只有一个特定的根结点. 结点的度:结点拥有子树的数量{ 度为0:叶子结点/终端结点. 度不为0:非终端结点/分支结点(除去根结点其它称为内部结点).} 树的度:树中所有结点的 ...

  4. 批量改ID 行形式

    update [Temp_Sql] set ID(字段) = (274+ID(字段))  字段+字段形式 可以以行形式批量修改

  5. linux系统下的日志,此日志对于系统安全来说是非常重要的一 个机制!!

    var/log/messages /etc/logrotate.conf 日志切割配置文件 (参考https://my.oschina.net/u/2000675/blog/908189) dmesg ...

  6. CSS column 布局总结

    有时候 第一列 底部会跑到顶部那里一部分.这时候应该这样. 在 每个 div前加上 display:inline-block

  7. C++_IO与文件2-用cout进行输出

    C++将输出流看作是字节流,在程序中,很多数据被组织成比字节更大的单位. 例如int类型由16位或者32位的二进制值表示:double值由64位的二进制数据表示: 但是在将字节流发送给屏幕时,希望每个 ...

  8. 教你搭建SpringSecurity3框架(附源码)

    源码下载地址:http://pan.baidu.com/s/1qWsgIg0 一.web.xml <?xml version="1.0" encoding="UTF ...

  9. UVALive - 3722 找规律

    题意:找规律 题解:找规律 结论是\(a^n(x-1)-\sum_{i=1}^{n-1}a^i \mod\ c\) #include<iostream> #include<algor ...

  10. es6 封装一个登录注册的验证滑块

    1,需求分析 滑块从左滑到右,开始滑.结束滑两种状态.两种状态显示的内容和样式的不同. 这是淘宝注册验证滑块的示例图 2,代码分析 const render = Symbol('render') co ...