AtCoder Regular Contest 126 E Infinite Operations
算是对这篇博客的补充吧。
设 \(a_1 \le a_2 \le \cdots \le a_n\)。
发现最优操作中一定是对相邻的数进行操作,因为如果 \(a_j\) 想把 \(x\) 给 \(a_i\)(\(i < j\)),最优是依次操作 \((j-1,j,x),(j-2,j-1,x),...,(i,i+1,x)\)。这样 \(x\) 就能造成 \((j-i)x\) 的得分。
最后全部数一定会无限趋近于 \(\bar{a}\)。考虑所有用到 \((i-1,i)\) 的操作的得分(拆贡献)。\(i \sim n\) 的数如果想把一些量给 \(1 \sim i-1\),就必须要用到 \((i-1,i)\)。那么贡献为:
什么意思呢?如果 \(a_i < \bar{a}\),意味着 \(\sum\limits_{j=1}^{i-1} \bar{a} - a_j > 0\),它们想要变成 \(\bar{a}\) 必须要跟 \(i\) 右边的大于平均值的数操作,所以贡献是 \(\sum\limits_{j=1}^{i-1} \bar{a} - a_j = \sum\limits_{j=i}^n a_j - \bar{a}\);否则 \(\sum\limits_{j=i}^n a_j - \bar{a} > 0\),它们想要变成 \(\bar{a}\) 必须要跟 \(i\) 左边的小于平均值的数换,所以贡献是 \(\sum\limits_{j=i}^n a_j - \bar{a}\)。
这样我们得到了最终的答案:
右项容易维护,问题变成了维护左项即 \(\sum\limits_{i=1}^n i \times a_i\)。注意因为前面的讨论假定 \(a_1 \le a_2 \le \cdots \le a_n\),所以这里的 \(i\) 实际上是排名(为了保证排名不重复需要强制重复的数按位置排序),所以单点修改相当于是加入/删除一个数。而加入/删除一个数又会让比他大的数的排名 \(+1/-1\)。
拓展一下,可以看成是维护 \(\sum\limits_{i=1}^n x_iy_i\),每次区间加 \(x_i\) 或 \(y_i\)。这个可以用线段树做,每个结点维护 \(\sum x_i, \sum y_i, \sum x_i y_i\) 即可。时间复杂度 \(O((n + q) \log (n + q))\)。