感觉失去卡常的兴致了……,虽然这个题明明不卡常。
Idea:ccz Solution:ccz Std:ccz Data:ccz
对这题的评价:3/11
题意简述
维护一个长度为 $n$ 的正整数序列 $a$ , $m$ 次修改序列中某个位置的值。
每次修改后问对序列重复进行以下操作,需要进行几次操作才能使序列变为全 $0$ (询问后序列和询问前相同,不会变为全 $0$ ):
选出序列中最大值的出现位置,若有多个最大值则选位置标号最小的一个,设位置为 $x$ ,则将 $a{x-1},a_x,a_{x+1}$ 的值减 $1$ ,如果序列中存在小于 $0$ 的数,则把对应的数改为 $0$ 。
$1\le n, m\le 10^5, 1\le a_i \le 10^9$ 。
主要思路
如果一个位置 $x$ 是极大值(即 $a_{x-1} < a_x, a_x \ge a_{x + 1}$ ),显然位置 $x - 1$ 和位置 $x + 1$ 不会成为最大值,且位置 $x$ 会成为最大值 $a_x$ 次。而操作过位置 $x$ 后,可能会出现新的极大值。
分析找极大值的过程,发现是从初始每个极大值开始向两侧隔一个位置取一个位置,直到到达极小值或边界为止。一个极小值仅当到两侧第一个极大值的距离均为偶数时才成为极大值。
所以对奇数位置和偶数位置分别开一棵树状数组维护一下,然后用一棵平衡树记录序列的极大值和极小值位置。这样就能够快速计算两个极值之间的区间的贡献。
对于单点修改,只会影响两侧最多分别两个区间,重新计算贡献即可。
时间复杂度 $O(n\log_2{n})$ 。
参考代码
写得好的话细节其实不多。
开始想要把两个极值之间的答案记在前一个极值上,然后发现很难写……
于是把极大值到两侧极小值这两段区间的答案记在极大值上,极小值上只记录自己有没有贡献。
然后由于要访问前两个和后两个极值,所以开始先插入一些初值即可减少讨论。
1 |
|