用矩阵表示变化&&线段树维护矩阵
用矩阵表示变化&&线段树维护矩阵
引入问题
- 已知一个数列
- 进行下面四种操作
- 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\) 的小常数,我吸氧后才勉强通过