函数库 线段树lazy标记

如果在题目中使某个区间所有元素的对应值*x或+-x,直接用线段树对每个元素进行计算,时间复杂度升高为nlogn,而用lazy标记可以减小时间复杂度。

假设需要对某区间+num;

void pushup(int p)
{//数值向上传递
    dat[p]=dat[2*p]+dat[2*p+1];
}
void pushdown(int p,int m)
{//将lazy标记传递给左儿子和右儿子,同时初始化自己的lazy标记,这样在未来的运算中,减少所走步数。
    if(add[p])
    {
        add[p*2]+=add[p];
        add[p*2+1]+=add[p];
        dat[p*2]+=(m-(m/2))*add[p];
        dat[p*2+1]+=(m/2)*add[p];
        add[p]=0;
    }
}
void update(int x,int y,long long num,int l,int r,int p)
{//更新每个节点的数值,与change函数类似,但是多了lazy标记的运算。
    if(x<=l&&r<=y)
    {
        add[p]+=num;
        dat[p]+=num*(r-l+1);
        return ;
    }
    pushdown(p,r-l+1);
    int mid=(l+r)/2;
    if(x<=mid)
    update(x,y,num,l,mid,p*2);
    if(y>mid)
    update(x,y,num,mid+1,r,p*2+1);
    pushup(p);
}
void build(int p,int l,int r)
{
    add[p]=0;
    if(l==r) {dat[p]=a[l];return;}
    int mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    dat[p]=dat[p*2]+dat[p*2+1];
}
long long find(int p,int l,int r,int x,int y)
{//计算区间和的时候,必须考虑到lazy标记的传递。
    if((x<=l)&&(r<=y))return dat[p];
    pushdown(p,r-l+1);
    int mid=(l+r)/2;
    if(mid>=y)return find(p*2,l,mid,x,y);
    if(mid<x)return find(p*2+1,mid+1,r,x,y);
    long long t=find(p*2,l,mid,x,y)+find(p*2+1,mid+1,r,x,y);
    return t;
}


posted on 2014-07-26 18:42  一锅土豆  阅读(143)  评论(0编辑  收藏  举报