加载中...

ABC 405 G(利用根号分块优化线段树log)

G - Range Shuffle Query

显然每次询问的东西是可重集排列数,因此只要在面对每次查询时维护好所有值的桶就行;\(<x\) 的所有值的桶的阶乘之积可以利用线段树查询维护。于是一个显然的做法:莫队离线处理所有查询,线段树维护每个子区间内值的桶的阶乘之积,每次修改一个元素需要在线段树上修改,总复杂度 \(O(n\sqrt n \log n)\)。然而本题 \(n, q\) 最高可达 \(2.5 \times 10^{5}\),无法通过。

问题在于每次修改时不能暴力地在线段树上做,需要使用其他维护前缀积的方式省去这个 \(\log\)。这里利用了分块,具体地,将所有值按 \(1\backsim n\) 分块,每一块维护对于当前查询区间,所有值的桶的阶乘之积。

分析复杂度(为了表述方便,默认 \(n,q\) 在同一量级):

  • 修改:增加 / 删除某个元素时,只需要修改该元素值所在块的信息,每次修改是 \(O(1)\) 的,故修改的总复杂度为 \(O(n\sqrt n)\)。(关键优化,省去线段树 \(\log\)
  • 查询:对于任意查询区间,完整的块的数量只有 \(O(\sqrt n)\) ,需要暴力查询非完整块内元素的数量也是 \(O(\sqrt n)\) ,故查询的总复杂度为 \(O(n \sqrt n)\)。(对于线段树维护的方式,查询复杂度是 \(O(n\log n)\),虽然查询变差了,但是优化了修改这一瓶颈)

综上所述,总复杂度为 \(O(n\sqrt n)\)

code_segtree_\(O(n\sqrt n \log n)\)

code_sqrtblock_\(O(n\sqrt n)\)

posted @ 2026-05-21 15:27  小橘奏  阅读(15)  评论(0)    收藏  举报