CF1793 - Codeforces Round

Codeforces Round #852 (Div. 2)

F. Rebrending

题意

区间长度为nn的数组a[i]a[i],且满足a[i][1,n]a[i]\in[1,n],有qq个查询区间[l1,ri][l_1,r_i],对于每个查询区间,求出
ali,ali+1,,ari1,aria_{l_i},a_{l_i+1},\cdots, a_{r_i-1},a_{r_i} 中相差最小的值,即

minj,k[li,ri]ajak\min_{j,k\in[l_i,r_i]} |a_j-a_k|

思路

该题不好直接构造线段树维护差值最小值,考虑离线做法.

令当前考虑右端点在 rr 处的查询 Sr={[li,ri]:ri=r}S_r = \{[l_i,r_i]: r_i = r\},设 dp(i)dp(i)aia_i{ai+1,,ar}\{a_{i+1},\cdots, a_r\} 的最小差值,即 dp(i)=min{aiaj:i+1jr}dp(i) = \min\{|a_i-a_j|:i+1\leqslant j\leqslant r\}.

从左到右依次扫描 rr,考虑如何使用 ara_r 更新 1ir11\leqslant i\leqslant r-1 的dp值.

l1=max{l:alar}l_1 = \max\{l:a_l\geqslant a_r\} 为距离 rr 最近且比 ara_r 大的值,若 i<l1<ri \lt l_1 \lt raial1+ar2\displaystyle a_i \geqslant \frac{a_{l_1}+a_r}{2},则 aia_ial1a_{l_1} 的距离不低于 aia_i,所以无需更新. 所以要找

l2=max{l:aralal1+ar2}l_2 = \max\left\{l:a_r\leqslant a_{l}\leqslant \left\lfloor \frac{a_{l_1}+a_r}{2}\right\rfloor\right\}

依此类推:

lk+1=max{l:aralalk+ar2}l_{k+1} = \max\left\{l:a_r\leqslant a_{l}\leqslant \left\lfloor \frac{a_{l_k}+a_r}{2}\right\rfloor\right\}

直到 alk=ara_{l_k} = a_r 或者 ={l:aralalk+ar2}\displaystyle \varnothing = \left\{l : a_r\leqslant a_l\leqslant \left\lfloor\frac{a_{l_k}+a_r}{2}\right\rfloor\right\},于是我们只需更新 l{l1,,lk}l\in\{l_1,\cdots, l_k\} 的dp值为 dp(l)=min{dp(l),alar}dp(l) = \min\{dp(l), a_l-a_r\}.

F题图解

对于 al<ara_l \lt a_ral>ara_l > a_r 处理类似,只需找

lk+1=max{l:alk+ar2alar}l_{k+1} = \max\left\{l:\left\lfloor \frac{a_{l_k}+a_r}{2}\right\rfloor\leqslant a_{l}\leqslant a_r\right\}

由于值域为 [1,n][1,n] 则更新节点数为 O(logn)\mathcal{O}(\log n),用线段树查找 lkl_k 用时 O(logn)\mathcal{O}(\log n),总计用时 O(nlog2n)\mathcal{O}(n\log^2n).

对于每个询问 [li,ri][l_i,r_i],当右端点 r=rir=r_i 时,答案为 minlil<ridp(l)\min\limits_{l_i\leqslant l \lt r_i}dp(l),用另一颗线段树记录dp值即可,用时 O(qlogn)\mathcal{O}(q\log n).

具体算法步骤:

  1. 离线全部询问,以右端点进行排序.
  2. 构造两颗线段树:
    1. key: Id, value: dp值,找区间最小值
    2. key: aia_i,value: Id,找区间最大值.

CF1793 - Codeforces Round
https://wty-yy.github.io/posts/39924/
作者
wty
发布于
2023年2月17日
许可协议