UOJ-783 新年的双区间操作
题意
给定一个序列 \(a\),给一个操作序列 \(m\),每个操作形如 \((l_i, r_i, x_i, l'_i, r'_i, y_i)\),表示如果区间 \([l_i, r_i]\) 最大值大于等于 \(x_i\) 则将区间 \([l'_i, r'_i]\) 对 \(y_i\) 取 \(\max\)。现在进行 \(q\) 次修改,每次先将 \(a_p\) 修改为 \(v\)(这个修改是 累积 的),然后 假设 依次执行整个操作序列,询问执行完后序列的最大值应该是多少。
题解
数据结构高妙题。
考虑一个操作 \(i\) 被触发的条件,要么是初始序列中有数能触发它(这是相对朴素的,运用后一种的处理方法一定能做),要么是有某一个操作 \(j\) 满足:\(j < i, [l'_j, r'_j]\cap[l_i, r_i]\neq\varnothing, y_j\ge x_i, \text{操作 j 被触发}\)。最终答案要么是原来序列的全局最大值,要么是所有被触发的操作中,\(y\) 最大的一个。这启发我们,不要正着去考虑 前面满足什么要求,才会触发操作 \(i\),而是递推 如果操作 \(i\) 被触发,会进一步触发的操作有哪些。这样我们只需要维护一个 \(y\) 的最大值,记作 \(f_i\)。
首先,区间有交这个限制,看起来就是非常丑陋,其它两个限制是个偏序关系的形式,有一火车皮的处理方法。又想到操作被反复统计不会有问题,所以把每个区间拆到线段树节点上,记下 \((x_i, f_i)\) 的信息,查询直接把 \([l'_j, r'_j]\) 放到线段树上,看能触发哪些后续操作。这样就是一个二位偏序加普通线段树问题,于是我们有经典 CDQ 分治。具体地,对操作序列分治,每次递归求完后半段答案以后,前半段按照 \(y\) 排序,后半段按照 \(x\) 排序。双指针加入后半段的操作,就能把两个偏序的限制都去掉,接下来直接在线段树上做区间取 \(\max\),区间求 \(\max\) 即可。这样预处理出了所有问题。时间复杂度是 \(\Theta(m\log n\log m)\)。