浅谈ZKW线段树之lazy标记

zkw线段树的网上讲解似乎很多,我就不介绍大纲了。

zkw线段树的核心思想就是尽量省去递归来减小常数

比如在build操作

普通线段树:

void build(int p,int l,int r)
{
    if (l==r){tree[p]=a[l];return;}
    int mid=(l+r)>>1,ls=p<<1,rs=p|1;
    build(ls,l,mid),build(rs,mid+1,r);
    updata(i);
}

zkw线段树:

void build()
{
    for (m=1;m<n;m<<=1);//--m;
    for (int i=1;i<=n;++i) t[i+m]=read();
    for (int i=m;i;--i) updata(i);
}
常数又小又简短

PS:上面注释部分可加可不加,不加维护\([0,n]\),加了维护\([1,n]\),想省事就别加了;
然而我想说的重点不在这里,如果你想学zkw线段树请右转zkw的论文《统计的力量》,
下面我将介绍如何在zkw线段树中使用\(lazy\)标记。

我们都知道如何在线段树上打标记。(没学过lazy标记就不要点进来)
我们只需要在对应区间打标记,这和普通线段树没什么区别。
但维护标记就比较麻烦了,这里有一种非常简单的维护方法

一般的zkw操作都是这样的

void change(int l,int r)
{
    for (l=l+m-1,r=r+m+1;l^r^1;l>>=1,r>>=1,updata(l),updata(r))
    {
        if (~l&1)   ...
        if (r&1)    ...
    }
    l>>=1;
    while (l) updata(l),l>>=1;
}

而我想说的更新方法非常简单,只需要在for()中加一个\(push\)函数

void change(int l,int r)
{
    for (l=l+m-1,r=r+m+1,push(l),push(r);l^r^1;l>>=1,r>>=1,updata(l),updata(r))
    {
        if (~l&1)   ...
        if (r&1)    ...
    }
    l>>=1;
    while (l) updata(l),l>>=1;
}

\(push\)函数长这样:

void push(int x)
{
    int top=0;
    while (x) sta[++top]=x,x>>=1;
    while (top>1) pushdown(sta[top--]);
}

上面的\(pushdown\)就是普通线段树的\(pushdown\)
代码的意思就是用模拟普通线段树的\(lazy\)下传;

是不是很好用,zkw线段树也能打标记,普通线段树可以退役了。

posted @ 2018-09-20 10:42 蒟蒻czx 阅读(...) 评论(...) 编辑 收藏