线段树 区间合并模板

区间合并是一类问题的总称包括以下操作
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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值