传送门luoguP2894
本题我们要维护最左边的值,考虑使用线段树维护。我们发现只用一个来存储当前的节点的值并不够,因为对于一个节点我们无法用一个来描述这整个区间哪些为空,哪些满了,例如查询的跨越了两个区间,我们就无法找到最左边的了。
所以我们考虑用多个变量描述该区间的状态:
lmx表示该区间最左边连续为空的个数,
rmx表示该区间最右边连续为空的个数,
len表示整个区间的总房间数,
sum表示整个区间的总空房间数。
这样我们可以很好的描述状态了,
对于一个节点的左房间数等于t[k].lmx,
若左儿子全空即t[lc].len=t[lc].sum,那么t[k].lmx=t[lc].sum+t[rc].lmx,
同理于右节点。
对于横跨两个节点的区间,
等于t[lc].rmx+t[rc].lmx左儿子的右房间数+右儿子的左房间数,
由于是区间更新,所以我们还要使用lazy_tag来做,
核心介绍完了,代码实现:
#include<bits/stdc++.h>
using namespace std;
#define lc k<<1
#define rc k<<1|1
const int N=5e5+5;
int n,m;
struct node
{
int lz,sum,len,lmx,rmx,l,r;
//该节点懒惰标记,最大连续空房间数,房间总数,左边连续空房间数,右边连续空房间数
}t[N<<2];//4倍以上
inline void pushdown(int k)
{
if(t[k].lz==0) return;
if(t[k].lz==1)//开房
{
t[lc].lz=t[rc].lz=1;
t[lc].lmx=t[lc].rmx=t[lc].sum=0;
t[rc].lmx=t[rc].rmx=t[rc].sum=0;
}
if(t[k].lz==2