区间合并是一类问题的总称包括以下操作
1.将[a, b]中的所有数字改成0
2.将[a, b]中的所有数字改成1
3.询问[a, b]中最长连续的1的长度是多少
主要解决第三种操作,也就是PushUp 函数
void PushUp(const int& rt, const int& l, const int& r)
{
segtree[rt].ln = segtree[rt << 1].ln;
//当前区间的左区间的左端点肯定也是当前区间的左端点
// 所以以当前区间的左端点为起点的最长连续1长度肯定包含其左区间的对应值
//这一部分值先记下来
/*
比如[1,8]区间 (1 1 1 1) (1 1 0 1)
在未pushup时
tree[2*cur].left==4,tree[2*cur].right==4,tree[2*cur].all==4
tree[2*cur+1].left==2,tree[2*cur+1].right==1,tree[2*cur+1].all==2
执行完tree[cur].left=tree[2*cur].left后tree[cur].left==4
但显然以当前区间的左 连续段的长度还需要算上右区间中的一部分
所以要执行tree[cur].left+=tree[2*cur+1].left 然后tree[cur].left==6
即为正确结果
*/
segtree[rt].rn = segtree[rt << 1 | 1].rn;//原理同上
segtree[rt].mn = max(segtree[rt << 1].rn + segtree[rt << 1 | 1].ln,
max(segtree[rt << 1].mn, segtree[rt << 1 | 1].mn));
//显然当前区间最长连续段要从左右区间的最长连续段取最大值 但这样就足够了吗?
//tree[cur].all的值不止要从左右子区间的最长连续段中择最大
//还要考虑该区间隐含的"中间连续段"
/*
比如[1,12]区间 (1 1 1 0 1 1) (1 1 0 1 1 1)
在未pushup时
tree[2*cur].left==3,tree[2*cur].right==2,tree[2*cur].all==3
tree[2*cur+1].left==2,tree[2*cur+1].right==3,tree[2*cur+1].all==3
只考虑从左右区间的最长连续段取最大值的话 即执行tree[cur].all=max(tree[2*cur].all,tree[2*cur+1].all)之后
tree[cur].all==3
但显然中间有四个连续的1被漏掉了
*/
int mid = (l + r) >> 1;
if(segtree[rt << 1].mn == mid - l + 1)
{//通过上面的描述,我们可以知道如果左区间都满足条件是,还需要加上右区间的值
//右区间同理可以得知
segtree[rt].ln += segtree[rt << 1 | 1].ln;
}
if(segtree[rt << 1 | 1].mn == r - (mid + 1) + 1)
{
segtree[rt].rn += segtree[rt << 1].rn;
}
}