[toc]
题意简述
给你 $n$ 个区间 $[l_i,r_i]$,选出 恰好 $k$ 个,使得交集最大。输出最长的长度和方案。
注:区间 $[l,r]$ 的长度被定义为 $r-l$。
$1\le k\le n\le 10^5$。
思路框架
若干的区间的交集,显然,左端点是所有左端点的最大值,右端点是所有右端点的最小值。
然后我们枚举左端点的最大值。怎么枚举呢?按左端点从小到大排序,枚举到 $i$ 表示只能用 $i$ 之前的区间。那么所有的左端点就都 $\le l_i$ 了。
然后这个时候我们怎么选最大值呢?
- 我们只能在 $1\sim i$ 中选
- 选择 $k$ 个使得最小值最大
怎么选择 $k$ 个使得最小值最大呢?那肯定是从大到小排序之后选前 $k$ 个啊!然后这时候最大的最小值,就是从大到小之后排第 $k$ 位的数。那么我们现在就是要支持动态插入(无删除)的第 $k$ 大。可以用对顶堆做。
对顶堆如何做
维护一个小根堆(堆顶是最小值),和一个大根堆(堆顶是最大值)。我们默认把数字插入到小根堆中,如果小根堆中的数字个数 $>k$,那么我们把小根堆中的 最小值 放到大根堆里。
那么有一个显然易证的性质:大根堆中的所有数,任何时候都 $\le$ 小根堆中的所有数。也就是,大根堆的堆顶 $\le$ 小根堆的堆顶。
而且我们还保证了小根堆中只有 $k$ 个数。那么这 $k$ 个数 $\ge$ 当前的其它所有数,显然,这 $k$ 个数字就是前 $k$ 大。求出这 $k$ 个数中的最小值(小根堆顶),就是当前的第 $k$ 大。
这个办法也可以用于求中位数 (也就是 $k$ 不一定静态,单调递增的情况也可以求)
代码
1 |
|