如果只有1个元素,显然可以维护一个栈。
赋值相当于在栈中插入一个元素。维护bz[i]表示i操作是否被撤销。
撤销操作可以不断的把栈中bz=1的元素删除直到栈顶bz=0。
由于每个元素只会被删除一次,所以时间复杂度正确。
这给了我们一些启示。
考虑分块。对于每个块维护一个栈,栈顶表示最后一次有效(没被撤销)的整块赋值。
还是维护bz[i]表示i操作是否被撤销。
对于每个元素维护一个栈。
由于某个元素可能被赋值多次,但是最后每个元素最多被赋值(sqrt{n})次。
所以使用n个链表维护元素栈。
维护每个块的和ans。
在赋值时,对赋值的整块的块栈中都插入一个元素,同时更新ans。
对散块对赋值操作作用的每个元素栈插入一个元素,且重构被更新的散块。
在查询时,我们在查询时遍历所有整块,并把它们的ans加起来。
在查询散块时,取这个散块被整体赋值/单点赋值的最晚操作更新答案。
在撤销时,更新bz。
对于整块,删除块顶部bz=1的元素。同时更新ans。如何更新后面会说。
对于散块,重构整个块。
在重构时,求出块内每个元素最晚被赋值的时间(a),并且把a以时间从小到大进行排序。
求出赋的值的后缀和(s)。(s_i=s_{i+1}+a_i)。
对于每个块维护last表示块内最晚被重构(最晚被单点赋值)的时间
对于每个块维护p,表示最小的p使得a[p]>=last
注意要把(s_0)加上从未被赋值过的元素。
取出这个块的栈的顶部(最晚的整块赋值)。
如果这个操作的时间(设为v)>块内元素最晚被散块赋值的时间,则这个块的ans=块的大小。
否则,把p赋值为0,暴力更新p,这个块的(ans=p*整块赋值的值+s[p])。
同时更新last。
在删除后更新整块的ans时,更新pt
取出这个块的栈的顶部(最晚的整块赋值)。
如果这个操作的时间(设为v)>last,则这个块的ans=块的大小。这是因为在散块赋值后就有个整块赋值,导致散块赋值无效。
否则,由于在重构前,这个块被撤销的操作的时间都是单调递减的,所以维护p可以暴力把p向前移动。
为什么是last?因为last前的操作已经被移动过了。
这个块的(ans=p*整块赋值的值+s[p])。
在排序的时候,如果我们选择基数排序,排序的基为(255)约等于(sqrt{n}),则对cache友好,只会排2次。
且由于重构操作只有n次,所以时间复杂度为(nsqrt{n})。
类似CF1178G的分析,可以得到时间复杂度为(nsqrt{n})
综上,我们在(nsqrt{n})的时空复杂度解决了这个问题。