CF1051G
标签
并查集,线段树合并对于一个包含 \(k\) 个数对 \((a_i, b_i)\) 的集合 \(S\),记 \(f(S)\) 表示执行以下操作让所有 \(a_i\) 均不同的最小代价。
- 选择一个 \(i\),若存在 \(i \ne j, a_i = a_j\),可以花 \(b_i\) 的代价使 \(a_i + 1\)。
- 选择一个 \(i\),若存在 \(j, a_i = a_j + 1\),可以花 \(-b_i\) 的代价使 \(a_i - 1\)。
给定 \(n\) 对 \((a_i, b_i)\),对于 \(k = 1, 2, \dots , n\),求出有 \((a_1, b_1) \sim (a_k, b_k)\) 组成的 \(S\) 的 \(f(S)\)。
\(n \le 2 \times 10^5\)
先考虑对连续的一段数,最后会变成什么?假设有 \(c\) 个数,最小的为 \(x\),那么这 \(c\) 个数最后会变成 \(x, x + 1, x + 2, \dots ,x + c - 1\)(因为没有 \(c - 1\),所以无法变得比 \(c\) 更小。)
考虑到让 \(a_i \pm 1\) 的代价可以抵消,不妨先让所有数都变成 \(x\),再把它们变成 \(x, x + 1, \dots\)
-
前面这个部分的代价是 \(-\sum (a_i - x)b_i = \min\{a_i\}\sum b_i - \sum a_i \cdot b_i\)。
-
后面的部分,肯定是贪心的让 \(b_i\) 大的少移动,小的多移动,从而减小代价。也就是如果 \(b_i\) 从大到小的排名为 \(k_i\),则它的代价是 \(b_i(k_i - 1)\)。
于是我们就计算出了单个 \(S\) 的代价,现在考虑插入。
不难想到,插入一个元素其实就是进行连续段(连通块)进行合并。合并时第一个部分比较好处理,维护 \(\min \{a_i\}, \sum b_i, \sum a_i \cdot b_i\), 即可。后面的部分可以对于 \(b\) 建出值域线段树,维护区间的 \(b\) 的个数以及 \(\sum b\),然后进行线段树合并即可。
合并时考虑 \(a_i - 1, x + c - 1, x + c\) 这三个位置即可(比较特殊的是 \(x + c - 1\),即如果之前没有数是 \(x + c - 1\),以后出现也要算在内,\(a_i - 1, x + c\) 是当前连续段左边、右边相邻的那个)。
计算贡献时,先减掉原来两段的,再加上合并完那一段的即可。
时间复杂度:\(O(n \log V)\),虽然这个题 \(V = n\)
浙公网安备 33010602011771号