算法 {查询区间连续子数组1的最大长度}

算法 {查询区间连续子数组1的最大长度}

普通版本

初始时A[111...111] 全是1, 每一次 将A[x] = 0, 然后查询[l-r]里面 连续1的最长长度, 比如[110111]l=1, r=4 (1011) 最长长度是11 (2);

这可以用线段树维护:
[l...r], Ma: 就表示答案(即这个区间的连续1的最大长度), MaPre: 从[l]开始的连续1的长度(A[l]如果为0则MaPre=0), MaSuf: 从[r]开始的连续1;

void Merge( Info_ const& _lef, Info_ const& _rig){ // `lef=[0-1];  rig=[2-3]`  则当前区间是`[0-3]`, 你需要根据`lef,rig`的信息 来推导出`[0-3]`区间的信息;
    Interval = {_lef.Interval.first, _rig.Interval.second};
     
    Ma = std::max( {_lef.Ma, _rig.Ma, _lef.MaSuf + _rig.MaPre});
    MaPre = (_lef.MaPre == _lef.Length() ? _lef.Length()+_rig.MaPre : _lef.MaPre);
    MaSuf = (_rig.MaSuf == _rig.Length() ? _rig.Length()+_lef.MaSuf : _rig.MaSuf);
}

隔板版本

初始时A[111...111] 全是1, 每一次 在A[x,x+1]的中间 放一个隔板, 然后查询[l-r]里面 连续1的最长长度, 比如[111(0)111]1(0)11 的最长长度是11 (2);

还是用线段树 节点信息和含义 和普通版本的完全一样, 唯一不同的 是Modify_index;
比如 我们要在x,x+1的中间 放一个隔板, 那么此时要修改: 将节点[x,x]MaSuf = 0 这表示 他不可以和x+1拼接, 同时将[x+1,x+1节点的MaPre=0;

Modify_Index(){
	//>> 使用`_modVal`来更新`info`;
    if( _modVal == 0){
        info.MaSuf = 0;
    }
    else{
        info.MaPre = 0;
    }
}

修改操作 即在`(x,x+1)`之间放一个隔板
Seg.Modify_index( x, 0);
Seg.Modify_index( x+1, 1);

应用

@LINK: https://leetcode.cn/problems/block-placement-queries/description/;
模板题;

错误

先看一个思路 (我没试 不保证正确), 把隔板 也看作是元素 转换成上面的普通版本, 即原数组[0,1,2] 对应新数组[0,(1),2,(3),4]奇数下标为隔板, 每次查询时 做下标转换后 查询最长长度 去掉隔板的;
哦, 这是错误的…, 因为 比如最长长度是[l...r] 但是你不知道他里面有多少个隔板啊 因为你不知道l,r 你只知道r-l+1的值;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值