20-12-17随笔---深入理解线段树lazy_tag操作

第二十一次CSP认证第五题:
给你n个三元组(x,y,z);进行m次操作;
每次操作:
1.给 [ l , r ] [l,r] [l,r]的三元组每个都加上 ( a , b , c ) (a,b,c) (a,b,c)
2.给 [ l , r ] [l,r] [l,r]的三元组每个都分别乘以 k k k
3.对 [ l , r ] [l,r] [l,r]的三元组进行置换,即 ( x , y , z ) (x,y,z) (x,y,z)置换为 ( y , z , x ) (y,z,x) (y,z,x)
4.查询 [ 1 , n ] [1,n] [1,n]的三元组的和的模;
( n   < =   1 0 18 , m   < =   1 0 5 ) (n \ <=\ 10^{18} , m\ <=\ 10^5) (n <= 1018,m <= 105)

分析:
这道题是一个非常经典的线段树;
这道题对于 80 % 80\% 80%的数据,是 n < = 1 0 6 n <= 10^6 n<=106的;
先对于 80 % 80\% 80%的数据考虑:首先对于加法和乘法,这个是非常经典的加法和乘法 t a g tag tag。对于剩下的置换,也是可以通过一个 t a g tag tag来解决的。
我们来好好分析加法 t a g tag tag和乘法 t a g tag tag的过程。

对于一段待处理的区间 [ l , r ] [l,r] [l,r],递归到当前层时,当前层的 t a g tag tag标记都已经传递到下面去了,当前这一层是没有 t a g tag tag的。也就是说,在递归进入这一层的时候,只需要处理自己这个操作的 t a g tag tag就行了。那 t a g tag tag之间的相互影响应该在什么时候处理呢?

应该在 p u s h d o w n pushdown pushdown中处理。在 p u s h d o w n pushdown pushdown操作中,是将当前层的 t a g tag tag传给自己的子区间。这里最重要的就是考虑一下运算的优先顺序。
我们令sum[node][0/1/2]表示 ( x , y , z ) (x,y,z) (x,y,z)的值,add[node][0/1/2],mul[node]分别表示加法tag和乘法tag,change[node]表示置换的次数(显然这里的置换次数是以3为周期的)。
这里change[node]会改变过去的mul[node]和add[node],而mul[node]会改变过去的add[node],add[node]不能改变其他的。
所以这里的tag的考虑顺序应该是change[node],mul[node],add[node];也就是在三个tag都存在的情况下,优先处理change[node],并将mul[node]和add[node]也改变。考虑mul[node]的时候也要改变add[node]。

而要完成这一题,还差一环,那就是在n很大的时候不能直接开点怎么办?这里就需要离散化,因为真正用到的点数只有 2 ∗ m 2*m 2m个,只需要将要用到的点离散化处理就可以了,计算的时候要记录每个点的真实坐标。


21.07.24补:
最近又写了一道线段树的tag题(hdu多校第二场的I love data structure),更深入的理解了lazy_tag的思想。
首先我们定义tag的优先级,假设 t a g 1 > t a g 2 tag1>tag2 tag1>tag2,那么tag1的值变化的时候,tag2会受到影响,tag2变化的时候,tag1的值不会受到影响。对于CSP那题来说就是乘法tag变化的时候,会影响加法tag,加法tag变化的时候不会影响乘法tag。置换tag会影响加法和乘法tag,而加法、乘法tag变化的时候不会影响置换tag。所以优先级 置换tag > 乘法tag > 加法tag。

另外我们要明确,在tag是进行pushdown传递的,所以tag之间的相互影响必须在pushdown的时候解决,高优先级影响低优先级的tag。在pushdown后,所有的tag都是直接作用于线段树中原来的值,作用顺序是先进行高优先级操作,再进行低优先级操作(因为tag之间的相互影响已经处理)。

还有一种比较特殊的情况,那就是相同优先级,也就是两个tag会相互影响。
这个在2021hdu多校第二场的"I love data structure"中体现了。序列中每个点有个 ( a i , b i ) (a_i, b_i) (ai,bi),每次操作为:

  1. [ l , r ] [l,r] [l,r]中的 a a a或者 b b b同时加上一个数
  2. [ l , r ] [l,r] [l,r]中的 a a a b b b交换
  3. [ l , r ] [l,r] [l,r]中的 a a a, b b b变成 3 a + 2 b 3a+2b 3a+2b 3 a − 2 b 3a-2b 3a2b
  4. [ l , r ] [l,r] [l,r]中的 ∑ i = l i = r a i ∗ b i \sum_{i =l}^{i =r}{a_i * b_i} i=li=raibi

通过上面的分析,我可以发现,加法tag(tag1)不能影响任何一个tag的值,而交换tag(tag2)可以影响tag1,也可以影响变换tag(tag3);tag3也可以影响tag1和tag2。这就说明2,3操作在tag优先级上是相同的,只取决于两个操作的到达顺序。但是对于到达的顺序必须要保存下来,这样操作就必须用个vector存下顺序,或者用其他操作。
这道题巧妙的地方在于,使用了矩阵进行加速运算。用矩阵来代替vector,可以将运算速度提升为常数级别的。
定义矩阵:
X = ( a b ) \mathbf{X} = \left( \begin{array}{cccc} a\\ b\\ \end{array} \right) X=(ab)
然后考虑转移矩阵:
S w a p = ( 0 1 1 0 ) \mathbf{Swap} = \left( \begin{array}{cccc} 0 & 1\\ 1 & 0 \\ \end{array} \right) Swap=(0110)
c h a n g e = ( 3 2 3 − 2 ) \mathbf{change} = \left( \begin{array}{cccc} 3 & 2\\ 3 & -2 \\ \end{array} \right) change=(3322)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值