线段树标记[wip]
线段树
我们刻画线段树所能维护的,
信息类型
首先我们考虑最简单的单点修改区间查询,我们会发现我们需要有一个信息类型 \(I\) (I for infomation) 满足
1.存在合并运算 \(+\) (使得 \(I\times I\rightarrow I\))(令 \(\times\) 为笛卡尔积).
这一要求是确保信息合并后仍然为信息.
2.合并运算满足结合律(即 \((I_1+I_2)+I_3 = I_1+(I_2+I_3)\)).
这一要求使得结果与合并(时加括号的)方式无关,从而使得提前计算部分结果成为可能
3.(1)合并运算应该具有较低的合并复杂度 或 (2)信息类型满足存在逆元且交换且合并单点信息及其逆元较易且我们可以较快的从信息中提取真正需要的部分(一个必要的要求是,合并应该具有与合并的单点处信息的数量(或者说区间长度?)低于线性的关系,否则的话,不优于每次询问直接分治合并)
这一要求是与实际的需求接轨,下面会看到相关的例子.
(1) 和 (2) 实际上对应了两种计算方式.
(1) 是修改后进行 pushup
(2) 是对覆盖的每一个节点单独修改
思考
我们发现,要求3并不好刻画(画风从群论跳到复杂度上了,这也使得它很不自然)
而忽略要求3的话,我们会得到一个半群的结构,这就是使用线段树(还能保证正确性)的最低要求.
信息举例
给出一些常见的信息类型用于举例
信息/合并方式
1.整数/和
\(I:x\) / \(I_1+I_2:x_1+x_2\)
这个信息类型满足交换律,结合律,存在单位元\(E:x=0\),可逆
2.线性函数(系数为整数)/复合
\(I:f(x)=kx+b\) / \(I_1+I_2:f_1(f_2(x))\)
这个信息类型满足结合律,存在单位元 \(E:f(x)=x\)
而值得注意的是它没有交换律,因此结合顺序不能随意交换,同时也不可逆(考虑 \(k=0\)),因此基于差分的结构(比如树状数组)不好维护它.
更一般的函数/复合 (当然)也可以看作信息类型,但这样往往不满足要求3而难以实用
3.集合(元素为整数)/集合的并
\(I:S=\set{ a_0, a_1, ... a_n }\) / \(I_1+I_2:S_1\cup S_2\)
这个信息类型满足结合律,交换律,存在单位元\(E=\emptyset\)
但这个信息类型(在常见情况下)不好合并,且这不是多重集,不可逆,因此不太好用线段树维护.(更具体的,考虑维护颜色数)
4.多重集/多重集的并
\(I:S=\set{ a_0, a_1, ... a_n }\) / \(I_1+I_2:S_1\cup S_2\)
这个信息类型满足结合律,交换律,存在单位元\(E=\emptyset\),且存在逆元(如果认可元素个数可以为负数)
那么这个信息类型虽然(在常见情况下)不好合并,但如果最后不需要完整的多重集(比如我们只求某个值是否出现,或者值的前驱后继等),那可以用 3(2) 的方式维护.(更具体的,这就是树套树)
5.整数/右值
\(I:x\) / \(I_1+I_2:x_2\)
这个信息类型满足结合律的,没有交换律,没有逆元,任何值都是左单位元但没有右单位元
但显然并没有人会用线段树维护这个问题,这警示我们问题的具体性质同样值得注意,虽然信息1有逆元,交换律以及单位元等条件,但维护它(单点修改/区间查询)的复杂度并不如信息5.
这里还有一些有启发性的例子包括 \(I:x\) / \(I_1+I_2:-x_2\) (这个没有任何单位元,而且查询长度为 \(1\) 时特殊) \(I:\{x,y\}\) / \(I_1+I_2:\{-x_1,-y_2\}\)(这个与两侧均有关且中间不能"直接"丢掉)
标记类型
考虑区间修改区间查询,我们往往需要一个标记类型 \(T\) (T for tag) 满足
1.存在合并运算 \(*\) (使得 \(T\times T\rightarrow T\))(令 \(\times\) 为笛卡尔积).
这一要求是确保标记合并后仍然为标记.
2.这一运算满足结合律(即 \((T_1+T_2)+T_3 = T_1+(T_2+T_3)\)).
这一要求使得结果与合并(时加括号的)方式无关, 实际上标记的情况可以看作每一个节点上存在时间轴上的一个队列, 存在的标记是这个队列里标记的复合.
3.存在作用运算 \(*\) (使得 \(T\times I\rightarrow I\))(令 \(\times\) 为笛卡尔积)(且满足 \(T_x*(I_1+I_2) = T_x*I_1 + T_x*I_2\))
也就是这一标记类型可以作用于信息类型, 且这一作用具有分配律.
4.存在单位元 \(E\) (使得 \(T_x\times E=T_x\), \(I_x\times E=I_x\))
也就是我们允许空标记的存在用来处理没有修改的情况以及下传后的情况
但这并不是一个真正的要求
为什么说它不是一个真正的要求呢?
对于实际的程序设计来说, 很容易添加一个 bool 变量 is_empty 表示是否存在标记, 从而强行在标记类型内引入单位元, 例如, 考虑信息 n.
5.合并运算和作用运算要有较低的复杂度(或者均摊复杂度,但(标记作用运算均摊复杂度)我没见过)
思考
实际上引入单位元也是处理半群的经典思路, 数学和信息学达成了某种统一((()))
待补