• 线段树标记顺序问题


    作者:sshwy

    黄队稳了!

    引言

    首先,在具备基础的线段树知识后,我们以结构化的语言描述线段树维护序列区间变动信息的方式:

    首先有若干种对序列区间的数据的操作(alpha_1,ldots,alpha_k),以及若干种数据分析操作(求值)(eta_1,ldots,eta_l)。在代码实现的过程中我们通常对每种操作使用一个标记(a_1,ldots,a_k),对每种分析维护一个权值(b_1,ldots,b_l)。这些标记和权值构成了线段树上一个结点的信息。

    使用线段树维护的信息,需要满足 (eta_1,ldots,eta_l) 都具有结合律或者前缀结合律。说白了,就是能够用左右儿子的信息来更新父节点信息。

    对于操作,我们要求他们能快速求值。也就是说每个操作(alpha_i)对应一个方法(A_i(u,v)),表示对结点(u)代表的区间施加(alpha_i)操作,参数为(v)。该方法的复杂度应是(O(k+l))的。通常来说,(A_i(u,v))会对(u)的权值和标记都产生影响。它会把(u)的权值更新为,进行了(alpha_i)参数为(v)的操作后的权值,并累加(alpha_i)操作对应的标记。(u)结点的标记是指(u)子节点的尚未进行的操作。说白了,(u)的权值是准的,而(u)子节点的权值是不准的。

    有标记,就有标记的下传。而这就关系到了下传的顺序的问题,也是本文要探讨的重点。

    先加还是先乘

    最经典的问题莫过于加乘标记下传问题:

    支持区间加,区间乘,区间求和。

    结论:先下传乘法标记,再下传加法标记。并且对于乘法操作对应的方法,它需要对加法标记做一定的影响。

    换言之,对 (u)父节点 (p) 的两个标记(p_{ ext{add}},p_{ ext{mul}}),则(u)被更新的过程为

    [egin{aligned} u_{ ext{sum}} &gets u_{ ext{sum}} imes p_{ ext{mul}} + p_{ ext{add}} imesell(u)\ u_{ ext{add}} &gets u_{ ext{add}} imes p_{ ext{mul}} + p_{ ext{add}}\ u_{ ext{mul}} &gets u_{ ext{mul}} imes p_{ ext{mul}} end{aligned} ]

    注:(ell(u))表示(u)对应区间的长度。

    可以发现这个更新本质上是先乘上了(p_{ ext{mul}}),再加上了(p_{ ext{add}})。并且(p_{ ext{mul}})影响了(u_{ ext{add}}),也就是标记之间的影响。

    那么为什么不能先加后乘?

    举个例子。对 (u)父节点 (p) 的两个标记(p_{ ext{add}},p_{ ext{mul}}),如果我们按照先加后乘的顺序更新

    [u_{ ext{sum}} gets (u_{ ext{sum}} + p_{ ext{add}} imesell(u)) imes p_{ ext{mul}} ]

    那么,我们考虑(p_{ ext{add}})怎么更新(u_{ ext{add}})

    我们不能直接(u_{ ext{add}}gets u_{ ext{add}} + p_{ ext{add}})。因为这就相当于是把 ((v+u_{ ext{add}}) imes u_{ ext{mul}}) 变成了 ((v+(u_{ ext{add}}+p_{ ext{add}})ell(u)) imes u_{ ext{mul}}),而我们想要的是((v+u_{ ext{add}}ell(u)) imes u_{ ext{mul}} + p_{ ext{add}}ell(u))。这里的(v)代指(u)的儿子结点。

    也就是说,我们必须把(u_{ ext{mul}})变成(1),才能(u_{ ext{add}}gets u_{ ext{add}} + p_{ ext{add}})。把(u_{ ext{mul}})变成(1),就意味着将(u)的标记下传。因此问题出现了:要下传(p)的标记,我们就得下传(u)的标记。因此复杂度就不对了。

    由此引出了一个问题:两个操作的先后顺序要通过怎样的性质来判断?

    再探先乘后加

    回到先乘后加的问题上。为方便后文表述,我们将更新前和更新后的权值做一个区分:

    [egin{aligned} u_{ ext{sum}}' &gets u_{ ext{sum}} imes p_{ ext{mul}} + p_{ ext{add}} imesell(u)\ u_{ ext{add}}' &gets u_{ ext{add}} imes p_{ ext{mul}} + p_{ ext{add}}\ u_{ ext{mul}}' &gets u_{ ext{mul}} imes p_{ ext{mul}} end{aligned} ]

    判断这个更新是否合法,主要是比较,对于(u)的子节点(v),将(v)先用(u_{ ext{add}},u_{ ext{mul}})更新,再用(p_{ ext{add}},p_{ ext{mul}})更新:

    [( v imes u_{ ext{mul}}+u_{ ext{add}}ell(v) ) imes p_{ ext{mul}}+p_{ ext{add}}ell(v) ]

    (v)(u'_{ ext{add}},u'_{ ext{mul}})更新:

    [v imes u_{ ext{mul}}'+u_{ ext{add}}'ell(v) ]

    看两者是否相等。显然,代入一下就可以发现,两者的确相等。

    这样,我们就可以总结出一般化的线段树多重信息维护方式。

    一般化

    对于操作(alpha_1,ldots,alpha_k),设它们对应的运算符分别为(igcirc_1,ldots,igcirc_k)。对于分析(eta_1,ldots,eta_l),设它们对应的运算符分别为(square_1,ldots,square_l)。那么称由(igcirc_i,square_i)和数值交替排列构成的算式为相关多项式

    我们定义变量结点,表示结点的信息都是变量。

    如果存在一种更新方式(ugets ext{upd}(u,p)),使得对于变量结点(v)( ext{upd}( ext{upd}(v,u),p))得到的相关多项式能与( ext{upd}(v,u))的相关多项式的结构一一对应(也就是说变量的系数可以不同,但与变量有关的运算过程是对应的),那么这种更新方式就是满足复杂度要求的,可以应用于线段树。

    应用 1

    操作:区间加、区间乘、区间赋值

    分析:区间和

    顺序:先区间乘,再区间加,最后区间赋值。

    则用(u)更新(v)

    [ ext{cover}(v_{ ext{sum}} imes u_m + u_aell(v),u_c) ]

    先用(u)再用(p)更新(v)

    [egin{aligned} & ext{cover}( ext{cover}(v_{ ext{sum}} imes u_m + u_aell(v),u_c) imes p_m + p_aell(v),p_c)\ = & ext{cover}( ext{cover}(v_{ ext{sum}} imes u_m imes p_m + (u_a imes p_m + p_a)ell(v),u_c),p_c) end{aligned} ]

    这样我们就得到了更新方程:

    [egin{aligned} u_m&gets u_m imes p_m\ u_a&gets u_a imes p_m + p_a\ u_c&gets ext{cover}(u_c,p_c) end{aligned} ]

  • 相关阅读:
    DCR挖矿成本¥355.92,市价¥346.24——五大币种挖矿成本分析 2018-08-7
    智者见智——区块链3.0与未来
    梭哈10万入场,拿住不放,3年后收益过十亿,币圈传奇—大空翼
    从路人甲到叱咤币圈的神话:“打死也不卖币”的宝二爷
    小白眼里的区块链和币圈 —— 持币待涨的故事
    区块链如何赋能网络互助行业?来自众托帮+区块链的应用、车车助+纷享车链AutoChain应用
    中国青年网记者-阿里巴巴王坚:互联网已成为世界发展的基础设施
    读者咩叭:畅谈经济未来
    中青网财经:请一位心理学博士当CTO 只有马云敢这么做
    云科技时代:阿里云创造者写了《在线》,这是一本怎样的书?
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/13938612.html
Copyright © 2020-2023  润新知