[BZOJ十连测]线段树

题目

题目概要
对于一个长度为 n n n 的序列,对其进行 m m m 次操作,每次操作将一个区间内的所有值赋值为区间内的最大值。

m m m 次操作全部告知,对于每组询问 ⟨ l , r , k ⟩ \langle l,r,k\rangle l,r,k ,输出进行了 [ l , r ] [l,r] [l,r] 中的所有操作后, a k a_k ak 的值。

数据范围与约定
n , m , q ≤ 1 0 5 n,m,q\le 10^5 n,m,q105

思路

注意到一个长臂政策:

  • 如果先后执行了两次操作 [ l 1 , r 1 ] , [ l 2 , r 2 ] [l_1,r_1],[l_2,r_2] [l1,r1],[l2,r2] ,满足 l 2 ≤ r 1 ≤ r 2 l_2 \le r_1 \le r_2 l2r1r2,那么 ∀ i ∈ [ l 2 , r 2 ] , a i ′ = max ⁡ j = l 1 r 2 a j \forall i\in[l_2,r_2],a'_i=\max_{j=l_1}^{r_2}a_j i[l2,r2],ai=j=l1maxr2aj

用一张图片来感受它。

在这里插入图片描述
如果先执行 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 的操作,显然的,公共部分 [ l 2 , r 1 ] [l_2,r_1] [l2,r1] 就变成了 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 的最大值。

此时再执行 [ l 2 , r 2 ] [l_2,r_2] [l2,r2] ,自然就使用了 max ⁡ i = l 1 r 1 a i \max_{i=l_1}^{r_1}a_i maxi=l1r1ai 更新整个区间的最大值。

所以说, [ l 2 , r 2 ] [l_2,r_2] [l2,r2] 中的元素都会被替换为 [ l 1 , r 2 ] [l_1,r_2] [l1,r2] 中的最大值。

有了这一点之后,我们可以放心地说,对于一些固定的操作,最终存在某对 l , r l,r l,r ,满足 1 ≤ l ≤ k ≤ r ≤ n , ∀ { a } , a k ′ = max ⁡ i = l r a i 1\le l\le k\le r\le n,\forall \{a\},a'_k=\max_{i=l}^{r}a_i 1lkrn,{a},ak=maxi=lrai

找到它的方法也很简单,只需要找,最远的可以传递到 a k a_k ak 的区间是谁。

在代码实现上,我们用树来表示这个关系,一个操作 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 的父节点是另一个操作 [ l 2 , r 2 ] [l_2,r_2] [l2,r2] ,且该操作满足 l 2 ≤ l 1 ≤ r 2 l_2\le l_1\le r_2 l2l1r2 ,在此基础上,还要求 [ l 2 , r 2 ] [l_2,r_2] [l2,r2] 的操作时间尽可能靠后,但是保持先于 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 的操作时间。

如何实现这棵树的维护呢?我们将询问离线下来,按照 r r r 排序,从左到右扫描,每加入一个新的操作区间,就在线段树上将区间内的每个点的 f f f 赋值为当前点。这样一来,一个区间的父节点,就是 f ( l ) f(l) f(l)

这是左端点,右端点同理。

光是“维护”还不够,我们需要倍增地找到最上面的一个,满足操作时间不小于 l l l

复杂度是啥捏?我也不知道诶 😂 大概是 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 的,可能有点常数。

代码

我自闭了……

等我有空了,可能会补上的吧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值