序列维护 题解集

记录一些比较神必的维护序列的题目。

线段树

P4681 [THUSC2015]平方运算

简要题意

给定一个序列,区间 .map([](int x) { x = x * x % p; });,区间求和。
p 给定,为小质数。\(N,M\le 10^5\)

题解

而把一个数看作一个点,向其平方取模连一条边,则最终必然构成一个基环森林,注意到 \(P\) 很小,每个数经过 \(11\) 次迭代之后就会进入环中。对于一个区间,如果区间中的每个元素都已经在环里,则区间所有元素所在环的大小的 \(\operatorname{lcm}\),即为区间的循环节。而对于题目给出的 \(P\)\(\operatorname{lcm}\le 60\),记为 \(C\)
先考虑初始是每个元素都在环内的时候怎么做:发现可以用线段树维护,对于每个区间,我们可以直接维护该区间的一个完整循环节,以及当前在循环节内的位置 now,则如果要对整个区间进行 \(k\) 次修改,则直接让 now 向前移动 \(k\) 即可,故可以 \(O(1)\) pushdown,如果一个区间的子区间被修改了,那么在 pushup 的时候直接根据两个子区间的循环节算出当前区间的循环节即可,复杂度 \(O(C)\)

如果一个区间内包含不在环内的元素,则无法维护循环节,我们只维护当前区间的和,需要 pushdown 时暴力递归向子区间 pushdown。由于每个元素经过至多 \(S=11\) 次操作后进入环,简单均摊分析发现这一部分增添的复杂度是 \(O(nS\log n)\) 的。

总时间复杂度 \(O(n\log n(C+S))\) 可以通过。

对于循环移位维护一个循环节和当前位置的指针是十分显然的。

record

P8969 Dream with Dynamic

简要题意

给定一个序列,区间加,区间 popcount,单点求值。

题解

注意到经过一次 popcount 之后值域 \(\in[1, \log V]\),故当一个区间经过 popcount 之后,所有的数被划分成了 \(\log V\) 个等价类,等价类内的元素在 popcount 之后相等,此时等价类内的 popcount 操作和加法操作可以看作赋值,可以维护,所以我们在每个节点出只要维护 \(\log V\) 个赋值操作即可:

\[tag=(popcounted,previous\_add,map) \]

\(popcounted=0\),则表示操作 \(i\mapsto i+previous\_add\),表示还没有经过 popcount 操作。
\(popcounted=1\),则表示操作 \(i\mapsto map(popcount(i+previous\_add))\),表示在 popcount 操作前做了的加法运算总和为 \(previous\_add\),然后进行了一次 popcount,这之后的操作被转换为 \(\log V\) 种赋值操作存储在 \(map\) 里。

考虑两个操作 \(u,v\) 的复合 \(u\circ v\),发现可以 \(O(\log V)\) 合并并且合并结果仍然可以表示为一个 \(tag\),故可以使用线段树维护,复杂度 \(O(n\log n\log V)\)

record
posted @ 2023-04-28 18:34  Watware  阅读(78)  评论(0编辑  收藏  举报