CF2096F Wonderful Impostors

题解

看到题意很容易想到用双指针来维护所有可行的区间,但是显然不能对所有的 1 区间来维护所有的可行区间,这样的区间数量会太多,我们无法快速进行判断。

所以只能对满足答案的所有区间进行双指针,这就要求我们如何快速插入和删除区间 0​ 区间和 1​ 区间。

我们维护一棵线段树表示节点 i 被 0 区间覆盖的次数,那么插入 1 区间的时候只用访问区间 min是否为 0 即可,插入 0 区间直接区间加。

需要注意的是,插入 0 区间的时候,可能会导致原来可行的 1 区间变得不可行。

我们不妨考虑它会让什么样的区间不可行?我们只需要对于左端点 ala_lal 找到一个向左的最长非零覆盖段 [cl,al)[c_l,a_l)[cl,al) 和右端点 ara_rar 找到一个向右的最长非零覆盖段 (ar,cr](a_r,c_r](ar,cr] (线段树上二分)。那么被 [cl,cr][c_l,c_r][cl,cr] 覆盖的所有 111 区间都会变得不可行,只需要用线段树来维护每个以节点 i 为 1 区间右端点的左端点最大值,相当于判断前缀 max 是否 ≥cl\geq c_lcl

删除操作怎么办?

加入一个区间后,如果使答案变得错误,我们需要将左端点对应的区间弹出,但是好像很难判断弹出之后的区间集合是否正确。

考虑我们在进行双指针的时候,一直保持当前区间集合的正确性,也就是说,我们可以尝试插入右端点,如果插入错误,我们马上将右端点带来的影响消除,然后删除左端点,直到可以成功插入右端点为止,那么在这个过程中就可以对于每一个右端点求出了一个最小的左端点,依此来判断答案即可。

自然的,由于保证了区间集合的正确性,那么我们删除左端点的时候只需要做逆操作就可以了,注意第二棵线段树的每个叶子节点需要用 set 来维护最大值。

时间复杂度 O(nlog⁡n)O(n\log n)O(nlogn)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值