用矩阵表示变化&&线段树维护矩阵

用矩阵表示变化&&线段树维护矩阵

引入问题

  • 已知一个数列
  • 进行下面四种操作
  • 1.区间赋值成 \(x\)
  • 2.区间乘上一个数 \(x\)
  • 3.区间加上一个数 \(x\)
  • 4.求出区间每一个数的和

洛谷P3373 (只有后面三种操作)

矩阵入门

可以看看我写的这篇博客

正文

线段树维护的是带有结合律的东西

假如维护的东西不存在结合律

那么每次一个新的标记就会把旧的标记挤下去

每一个标记都要遍历整棵树,复杂度变成 \(O(nm)\)

线段树维护矩阵

众所周知,矩阵乘法是有结合率

即 :

\(A(B C) = (AB)C\)

那么我们可以在线段树的每一个节点维护一个矩阵来表示一些信息

那么我们的每一次操作都想方设法把它变成"乘上一个矩阵"

那么我们就可以线段树维护区间矩阵乘法,来表示一些结合律不是那么明显的信息

注意 : 由于矩阵乘法不具有交换律,所以我们每次只能左乘,或只能右乘一个转移矩阵

左乘右乘 分别看个人实现的是一个列矩阵,还是一个行矩阵

矩阵模拟变化

每一个结点用矩阵可以表示成这样

\[\left[\begin{array}{c}v\\s\end{array}\right] \]

\(v\) 表示维护的权值(区间和),\(s\) 表示结点的大小


来按题目中的意思模拟

把原矩阵左乘一个矩阵来得到我们要的新矩阵

区间加 \(x\)

\[\left[\begin{array}{c}1&x\\0&1\end{array}\right]\times\left[\begin{array}{c}v\\s\end{array}\right]=\left[\begin{array}{c}v + s\times x\\s\end{array}\right] \]

区间乘 \(x\)

\[\left[\begin{array}{c}x&0\\0&1\end{array}\right]\times\left[\begin{array}{c}v\\s\end{array}\right]=\left[\begin{array}{c}v \times x\\s\end{array}\right] \]

区间赋值为 x

\[\left[\begin{array}{c}0&x\\0&1\end{array}\right]\times\left[\begin{array}{c}v\\s\end{array}\right]=\left[\begin{array}{c}s \times x\\s\end{array}\right] \]

区间求和

即按普通的线段树那样

把每一个结点的矩阵加在一起即可


对了,最好写一个矩阵类,弄个矩阵乘法加法之类的

由于矩阵运算有一个 \(8\) 的小常数,我吸氧后才勉强通过

最后放代码

\(\color {Deepskyblue} {Code}\)

posted @ 2019-10-16 17:32  Lskkkno1  阅读(470)  评论(0编辑  收藏  举报