[集训队互测2018]完美的队列

13 篇文章 0 订阅
12 篇文章 0 订阅

题目

传送门 to LOJ

思路

区间操作?线段树?想多了……由于 两个队列之间的差别很大,线段树难以维护区间信息。

没法从操作入手,我们就 从问题出发。它只问不同的数字,并且针对全局;而且每次加入都是相同的数字;又看到 a i ≤ 1 0 5 a_i\le 10^5 ai105 的限制,不难想到,对于每种数字求出它出现的时间段

然而对于某一种实在太宽泛。所以我们微调一下,求出 某次操作的所有数字都被弹出 的时间。

一个数字被弹出,就是在它之后又加入了 a i a_i ai 个数字嘛。用 t i ( x ) t_{i}(x) ti(x) 表示,从 x x x 时刻算起(不包含),到哪个时间,第 i i i 个队列中又加入了 a i a_i ai 个数字。那么对于第 x x x 个修改 [ l , r ] [l,r] [l,r] 的总耗时 T x = max ⁡ i = l    r t i ( x ) T_x=\max_{i=l}^{\;r}t_i(x) Tx=maxi=lrti(x) 。这里是区间操作了。但是线段树仍然无能为力。线段树在这种叶子元素相去甚远的题目中就是垃圾。

区间操作除了树,就只能想到 差分 分块 了。我们可以对于每个块,求出所有数字都被弹掉的时间。对于每个块的每个 x x x 我们都求出来!一共也才 O ( n B ⋅ m ) \mathcal O(\frac{n}{B}\cdot m) O(Bnm) 个嘛!(这里 B B B 是块的长度。)

具体怎么求呢?就是利用 t i ( x ) ≤ t i ( x + 1 ) t_i(x)\le t_{i}(x+1) ti(x)ti(x+1) 这一重要等式。我们可以 双指针,对于一个当前 l l l,移动出 r r r 使得 r = max ⁡ i ∈ B l o c k t i ( l ) r=\max_{i\in Block} t_i(l) r=maxiBlockti(l) ,然后增大 l l l ,继续移动 r r r

移动 r r r 的过程就是:覆盖整个 B l o c k Block Block 的操作,直接计数;对于部分覆盖的,暴力 修改。因为部分覆盖的情况较少,一共只有 O ( m ) \mathcal O(m) O(m) 对,所以复杂度 O ( B m ) \mathcal O(Bm) O(Bm) 可以接受。(这里计数怎么判断不用讲吧?就是暴力 “重构” B l o c k Block Block 时,求一下当前状态下至少需要多少次覆盖。)移动 l l l 就是撤销 r r r 的操作,复杂度相同。

现在还剩一个问题,零散的怎么处理?如果像整块一样,直接计算贡献,好像是 O ( n m ) \mathcal O(nm) O(nm) 的?回顾一下普通的分块——哦!零散的贡献次数应当为 O ( m B ) \mathcal O(mB) O(mB) 的!那么我们只需要避免无效贡献。所以,对每个 B l o c k Block Block 都记录与它有交(但不是完全包含)的操作,设其为 ⟨ d i ⟩ \lang d_i\rang di 。此时 ∑ ∣ d i ∣ = O ( m B ) \sum |d_i|=\mathcal O(mB) di=O(mB) 没有大问题。覆盖整块的操作可以先做出前缀和,否则复杂度会假。

同样的,可以对 ⟨ d i ⟩ \lang d_i\rang di 作双指针,道理和上面是一样的,只是要顺便用上前缀和数组罢了。不过 t i ( x ) t_i(x) ti(x) 并不一定是 d i d_i di 啊,也可能是某次整块覆盖操作。你傻呀?自己用 i f \tt if if 写一写就完事儿了!

复杂度 O ( m B + m n B ) ≥ O ( m n ) \mathcal O(mB+m\frac{n}{B})\ge\mathcal O(m\sqrt n) O(mB+mBn)O(mn ),在 B = O ( n ) B=\mathcal O(\sqrt{n}) B=O(n ) 时取等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值