CF1034D. Intervals of Intervals 题解

CF1034D. Intervals of Intervals

题意
给你 \(n\) 条线段 \([a_i,b_i]\),定义区间 \([l,r]\) 的价值为 \(l\le i\le r\) 的所有线段的并的线段长度。
给定 \(k\),求出选择 \(k\) 个不同区间的最大价值和。
\(1\le n\le 3\times 10^5\ , \ 1\le k\le \min(10^9,\frac{n\times(n+1)}{2} \ ,\ 1\le a_i\lt b_i\le 10^9)\)

思路
先思考如何求出所有 \([l,r]\) 的价值。
我们枚举 \(r\) 端点,把线段 \(1\sim r\) 加入考虑,我们维护所有 \([l,r]\) 的值,我们设 \(last(pos)\) 为最后一个覆盖 \(pos\) 的线段,没有为 \(0\)
那么区间 \([l,r]\) 就是求有多少 \(pos\) 满足 \(last(pos)\ge l\)
现在我们考虑 \(r\to r+1\) 会带来什么影响,加入 \(r+1\) 这条线段就相当于将 \(last(pos) \ pos\in [a_{r+1},b_{r+1}]\) 修改为 \(r+1\),而对于一个点 \(pos\),它的 \(last(pos)={r}'\to r+1\) 会对当前 \(r+1\) 端点的 \(l\in[r'+1, r+1]\) 全部 \(+1\),用线段树维护即可做的 \(\mathcal{O}(n\log_2 n)\),这相当于是把所有询问离线下来的做法,如果可持久化以 \(r\) 作为版本可以 \(\mathcal{O}(n\log_2^2 n)\) 在线做。

具体维护方法是用 ODT 维护颜色段,因为加入 \(r+1\) 线段相当于区间覆盖操作,每次增加一段颜色,删除若干段。因为每一段最多删除一次,所以总删除次数是 \(\mathcal{O}(n)\) 的,时间复杂度 \(\mathcal{O}(n\times \log_2n)\)

回到当前问题,我们显然可以二分第 \(k\) 大的区间价值是什么,然后通过算 \(w(l,r)\ge mid\) 的数量是否大于等于 \(k\) 来左/右移 \(mid\)
对于 \(check()\) 我们仍然选择枚举 \(r\),容易发现有性质 \(w(l,r)\ge w(l+1,r)\) 所以我们记录 \(L(i)\)\(w(x,i)\) 中最后一个满足 \(w(l,i)\ge mid\)\(l\)(没有满足的为 \(0\)),最终 \(check()\) 要求的就是 \(\sum_{i=1}^n L(i)\),可以在维护 \(w(l,r)\) 的线段树上二分求得,时间复杂度 \(\mathcal{O}(n\times log_2^2 n)\)

但是还有更快的方法,还有一个显然的性质 \(w(l,r)\le w(l,r+1)\) 所以 \(L(i)\) 是单调不降的,双指针维护即可做到 \(\mathcal{O}(n\log_2 n)\)
计算答案时先计算出 \(w(l,r)\gt mid\) 的和,因为 \(mid\) 的取值可能有多个,不一定能取完,算答案时用之前计算出的 \(L(i)\) 算区间和即可。
将 ODT 预处理提到二分外面,区间加用差分处理,最后计算答案时加上区间加的贡献,可以将线段树的 \(log\) 去掉。
最终时间复杂度 \(\mathcal{O}(n\log_2 n)\)

posted @ 2025-04-11 14:55  Qing_Nian  阅读(12)  评论(0)    收藏  举报