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

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

引入问题

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

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

矩阵入门

可以看看我写的这篇博客

正文

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

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

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

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

线段树维护矩阵

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

即 :

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

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

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

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

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

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

矩阵模拟变化

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

[left[egin{array}{c}v\send{array} ight] ]

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


来按题目中的意思模拟

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

区间加 (x)

[left[egin{array}{c}1&x\0&1end{array} ight] imesleft[egin{array}{c}v\send{array} ight]=left[egin{array}{c}v + s imes x\send{array} ight] ]

区间乘 (x)

[left[egin{array}{c}x&0\0&1end{array} ight] imesleft[egin{array}{c}v\send{array} ight]=left[egin{array}{c}v imes x\send{array} ight] ]

区间赋值为 x

[left[egin{array}{c}0&x\0&1end{array} ight] imesleft[egin{array}{c}v\send{array} ight]=left[egin{array}{c}s imes x\send{array} ight] ]

区间求和

即按普通的线段树那样

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


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

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

最后放代码

(color {Deepskyblue} {Code})

原文地址:https://www.cnblogs.com/Lskkkno1/p/11687044.html