SOJ1737 题解

题意

给定一个长度为 \(n\) 的串 \(S\)

定义 \(occ(T)\) 表示串 \(T\)\(S\) 中出现的次数。

\(q\) 次询问,每次询问给定一个区间 \([l,r]\),查询 \(S[l,r]\) 的所有子串的 \(occ\) 之和。

\(1\le n,q\le 2\times 10^5\)

题解

学到了新技能,来记一下。

这是一道看起来很典的题目。但实际上并不好做。

先思考 \(n^2\) 做法(也是我的做法)。可以想到一种转化,即求 \(\sum\limits_{i=1}^n\sum\limits_{j=l}^r\operatorname{lcp}(S[i,n],S[j,r])\)。离线后可以做到 \(O(n^2)\)。但这种做法已无法优化。

换一种,定义 \(f(T)\)\(T\) 的所有后缀的 \(occ\) 之和。建出后缀树,则若我们知道 \(T\)\(\text{sam}\) 的节点,可以 \(O(1)\) 求。此时原式等价于 \(\sum\limits_{i=l}^rf(S[l,i])\)。因为 \(S[l,l],S[l,l+1],\dots,S[l,r]\)\(\texttt{sam}\) 上是一条链,所以这种做法是 \(O(n^2)\) 的。

“链”的性质为接下来的优化创造条件。这里引进一种新科技:\(\text{DAG}\) 链剖分。我们想要这样的性质:\(\text{DAG}\) 上任意一条路径经过 \(O(\log P)\) 条链,其中 \(P\) 为路径总量,在 \(\text{sam}\) 上是 \(n^2\)。建链的方法如下:

  • 对所有节点,求以 \(i\) 为起点的路径数量 \(f_i\) 和以 \(i\) 为终点的路径数量 \(g_i\)
  • \(nxt_i\) 为所有 \(i\) 出点中 \(f\) 最大的点,\(pre_i\) 为所有 \(i\) 入点中 \(g\) 最大的点。
  • 若边 \((u,v)\) 满足 \(nxt_u=v\wedge pre_v=u\),则其为重边。否则为轻边。
  • 此时只保留所有重边,即可完成链剖。

证明一下上面的性质。若走一条轻边,必有 \(2f_v<f_u\vee g_v>2g_u\)。于是得证。

对于建链,另一种解释是:先由 \(nxt\) 建树,再由 \(pre\) 树剖。这样可以更直观地感受 \(\text{DAG}\) 链剖的妙处。

建出链后,利用前缀和进行优化,二分哈希找到何时跳出链。复杂度 \(O(n\log^2n)\)

posted @ 2023-02-16 10:11  realFish  阅读(81)  评论(0)    收藏  举报