do_while_true

一言(ヒトコト)

「杂谈」原来我不会线段树懒标记以及永久化

原来我不会线段树懒标记以及永久化。

虽然很多时候用线段树只是什么区间加区间和,区间加区间最值,区间推平区间求和等等,大部分都是不知背后的所以然就瞎打标记就 ok 了,没想到背后还有道理要探寻,免得最后自己跳进了坑里才发现是线段树/树套树没写对。


如果是正常打懒标记,是需要这个标记在时间轴上有结合律的,可以不满足交换律。

回想线段树懒标记下放的过程就可以感性理解是为什么,因为在打标记的时候我们把标记 \(t_3\) 下放了,后来的标记 \(t_3\) 一定在前面的标记 \(t_2\) 后面,所以不需要满足结合律,然而下放标记 \(t_2\) 的时候可能和前面的标记 \(t_1\) 合并,但 \(t_1\) 还没有和更前面的标记 \(t_0\) 合并,如果 \((t_2\to t_1)\to t_0\neq t_2\to (t_1\to t_0)\) 就 GG 了,这里的 \(a\to b\) 就是把两个标记 \(a,b\) 合并,前面的 \(a\) 合并到了 \(b\) 上面,是我瞎定义的符号,是为了突出这个运算是有先后顺序的。

比方说加法乘法标记我们维护了一个 \(ax+b\),如果两个标记 \(t_0=(a_0,b_0),t_1=(a_1,b_1)\) 把他们合并,最终的标记就是 \(t_1\to t_0=(a_0a_1,b_0a_1+b_1)\),假设有三个先后出现的标记 \(t_0,t_1,t_2\),我们发现 \((t_2\to t_1)\to t_0= t_2\to (t_1 to t_0)\)。这个就是标记在时间轴上具有结合律,但它没有交换律,\(t_1\to t_0=(a_0a_1,b_0a_1+b_1),t_0\to t_1=(a_1a_0,b_1a_0+b_0)\),这两个标记是不同的。


回想起标记永久化的过程,需要标记在时间轴上具有结合律,是不是必须要求标记在时间轴上有交换律呢?

其实是不必要的,只需要对于两个标记 \(a\to b\),如果能找到一个 \(a'\) 使得 \(a\to b=b\to a'\),在一个标记 \(a\) 在线段树上往下走的时候,如果当前节点有个标记 \(b\),让 \(a\) 变成 \(a'\) 就可以,因为标记永久化查询的时候不会 pushdown,所以运算顺序交换了一下,但原先是 \(a\to b\),不得不把 \(a\) 放在 \(b\) 后面合并,就把 \(a\) 变成 \(a'\),使得标记永久化查询到的 \(b\to a'\)\(a\to b\) 是等价的。

树套树的时候记得看一下能不能标记永久化。


线段树题要考虑:

  • 给区间整体打标记的时候,维护的值会发生什么变化;
  • 给区间整体打标记的时候,标记之间如何合并;
  • 是否能快速地 pushup

Reference

zhqwq 我 根 本 不 会 线 段 树|线段树再学习笔记

posted @ 2021-09-28 10:03  do_while_true  阅读(389)  评论(0编辑  收藏  举报