线段树扫描线详解
OI比赛中扫描线是一种很常用的算法,矩形周长是一个模板题。
基本思想
比如,对于下面的三个矩形:
想象有一条扫描线,从下往上扫描完整个图案,每遇到一条上边或者下边就停下来:
然后每次停下后对区间进行处理,用一个ans代表当前周长,最后ans就是答案。
代码实现
首先,要先把矩形拆成上边和下边,用1和-1分别代表上边和下边。然后按高度排序,这样数组从前往后处理就相当于扫描线从下往上扫描。如果是下边,就在对应区间上加1,如果是上边,就在对应区间上减1。
在整个区间上建一棵线段树:
#define lson o<<1
#define rson o<<1|1
#define mid (l+r)/2
struct Tree
{
int sum;//整个区间被整体覆盖了几次(类似lazytag,但不下传)
int num;//整个区间被几条互不相交的线段盖(比如,[1,2],[4,5]则为2,[1,3],[4,5]则为1(我习惯用闭区间),[1,4],[2,2],[4,4]也为1)
int len;//整个区间被覆盖的总长度
bool lflag;//左端点是否被覆盖(合并用)
bool rflag;//右端点是否被覆盖(合并用)
}//如果不懂也没有关系,接着往下看
那么pushup要怎么写呢?
void pushup(int o,int l,int r)
{
if(tree[o].sum)//此区间之前被一整个线段覆盖过
{
tree[o].num=1;
tree[o].len=r-l+1;