zoukankan      html  css  js  c++  java
  • 洛谷5113

    如果只有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})的时空复杂度解决了这个问题。

  • 相关阅读:
    spring学习总结003 --- IOC容器启动源码(BeanFactoryPostProcessor)
    spring学习总结002 --- IOC容器启动源码(BeanFactory)
    ubuntu上安装mysql
    kafka学习总结017 --- consumer配置参数之max.poll.interval.ms
    kafka学习总结016 --- consumer配置参数session.timeout.ms和heartbeat.interval.ms
    kafka学习总结015 --- consumer配置参数之auto.offset.reset
    kafka学习总结014 --- consumer多线程问题
    kafka学习总结013 --- kafka消费者API
    kafka学习总结012 --- 数据消费相关流程
    Java SAX解析
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/13740141.html
Copyright © 2011-2022 走看看