qbxt 突破营 Day7 T3

发布时间 2023-10-09 15:24:29作者: FOX_konata

小葱想要吃糖,小葱将拿出来的N颗糖排成一排,第\(i\)颗糖的美味值为\(a_i\)。小葱很喜欢吃糖,所以小葱会从\(N\)颗糖选择不超过\(K\)段不相交的区间的糖果吃掉。但是小葱同学不希望别人吃到和他美味度差不多的糖,所以对于一颗没被吃掉的糖,小葱希望这颗糖美味度比他吃的糖的美味度最大值还大或者比他吃的糖的美味度最小值还小,所有没被吃掉的糖都要满足这个条件。那么,小葱有多少种吃糖的方案呢?(两种方案不同当且仅当吃掉的糖不同,与选择的区间无关)

对于\(100\%\)的数据,\(1\leq N\leq 10^5,1\leq K\leq 5,1\leq a_i\leq 10^9\),所有\(a_i\)互不相同。

赛时想到了扫描线 \(+\) 线段树,但信息没有很好的利用起来,还想到了并查集 \(+\)\(+\) 倍增那去了,赛后还发现想假了,不做评价……

很容易想到 \(a_i \Rightarrow pos_i\) 的转化,也可以知道右端点扫描线,关键是线段树上维护什么?起初我想的是线段树上维护 \(0/1\) 表示当前是/否能成为答案。但显然区间的增减不好维护,因此我们改为在线段树上维护 \(i \sim r\) 被分成了多少个连通块

发现当加入一个数 \(a_{pos_r}\) ,会让线段树 \([1,r]\) 区间 \(+1\)\([1, a_{pos_r - 1}]\) 区间 \(-1\)\([1, a_{pos_r + 1}]\) 区间 \(-1\) ,原因容易想到

但怎么求 \(\leq K\) 的个数?(重点) ,我们发现可以在线段树每个节点上维护前 \(K\) 小的连通块大小和这个大小的个数(注意这个连通块大小是去重后再计算的,也就是说 1 2 2 2 2 2 3, K = 3 会被记录为 (1,1), (2,5), (3,1) )

合并时怎么合并?把两个区间暴力差在一起排个序再把前 \(K\) 大取出来即可,个数的合并时 trivial 的不讨论

复杂度 \(O(n K \log n)\)

其实线段树维护连通块个数并不难想,可能只是赛时的我傻逼了。但对于后面维护 \(\leq K\) 的个数是一个非常好的维护方式,可以参考