[线段树系列] LCT打延迟标记的正确姿势
这一篇博客将教你什么?
如何用LCT打延迟标记,LCT和线段树延迟标记间的关系,为什么延迟标记要这样打。
——正片开始——
学习这一篇博客前,确保你会以下知识:
Link-Cut-Tree,普通线段树
当然,不会也没有关系,你可以先收藏这篇博客,等你学了以后再来看。
最好通过了这一道题:【模板】线段树Ⅱ
没有通过也没关系,对于本篇的知识只是一个启发作用。
我们平时使用的Link-Cut-Tree一般只需要打一个翻转标记rev[x]。
然后我们用pushR(x)函数来下发翻转标记。
那么我们现在来看这样一道题:TreeⅡ
练习LCT打标记的绝世好题,可以说就是一道模板题了。
我们来看它需要维护什么:树的权值。
如果能把这个操作2去掉,树剖将绝杀,可惜换不得。
单走一个“树”,nice,直接LCT。
询问权值和,可以,给LCT来一个下传标记,开始你的操作秀。
我们直接来看pushdown部分:
操作有乘和加两种,根据运算法则,乘法优先,所以首先判断
if(lazM[x]!=1){...}
然后是加法
if(lazA[x]){...}
最后回到我们的翻转标记。
然后我们来看pushM和pushA部分
#define mul(x,y) x*=y;x%=MOD; inline void pushM(unsigned int x,unsigned int d){ mul(sum[x],d);mul(val[x],d);//节点信息直接更新 mul(lazM[x],d);mul(lazA[x],d);//按照运算法则先把乘标记乘了,再把加标记乘了}
有没有回想起什么?没错,就是线段树的懒标记。
我们看看线段树2的懒标记下传部分
void pushdown(int p){ mul(p<<1)=(mul(p<<1)*mul(p))%P; mul(p<<1|1)=(mul(p<<1|1)*mul(p))%P; add(p<<1)=(add(p<<1)*mul(p))%P; add(p<<1|1)=(add(p<<1|1)*mul(p))%P; sum(p<<1)=(sum(p<<1)*mul(p))%P; sum(p<<