线段树

线段树-概念

树上每个点对应序列上一段连续的区间

根节点:(1,n)

左儿子:(1,n/2)

右儿子:(n/2)

………………

叶子节点:对应一个点
层数:logn

共1+2+4+……+n=2n个节点

在节点上维护对应区间的信息


线段树-功能

首先我们需要一个define:

 

#define ls(k<<1)
#define rs(k<<1|1)
#define mid(l+r>>1)

 

1.单点加

将某一个数加v

x对应的叶节点+v

依次向上更新x祖先的信息

void pushup(int k,int l,int r){
    s[k]=s[ls]+s[rs]; //左右儿子更新该节点 
}
void plus(int k,int l,int r,int x,int v){  //将x位置点加v 
    if(l==r) return s[l]+=v,void();
    if(x<=mid) plus(ls,l,mid,k,v); //只找x所在区间 
    else plus(rs,mid+1,r,k,v);
    pushup(k,l,r);
}

 

2.区间求和

s[k]:k对应的区间和

s[k] = s[ls]+s[rs]

边界:当x为叶节点时s[k] = a[l]

按照二叉树形式从上到下从左到右依次给线段树上的节点编号

建树O(n):

void build(int k,int l,int r) {
    if(l == r) return s[k]=a[l],void();
    build(ls,l,mid);
    build(rs,mid+1,r);
    return s[k]=s[ls]+s[rs],void();
}

考虑当前节点k对应[l,r]与[x,y]关系

若[x,y]包含[l,r]计入;

否则若[x,y]包含[l,mid],递归ls,

若[x,y]包含[mid+1,r],递归rs

很显然:

int ask(int k,int l,int r,int x,int y){
    if(x <= l && r <= y) return s[k];
    int res = 0;
    if(x <= mid) res+=ask(ls,l,mid,x,y);
    if(y > mid) res+=ask(rs,mid+1,r,x,y);
    return res;
}

3.区间修改,区间求和--------懒标记

lazy[k]代表将k对应的区间整体加lazy[k].

当我们需要k对应区间加v时,选择lazy[k]加v代表这段加过v了(懒)

像这样↓

void ladd(int k,int l,int r,int v){
    s[k]+=(r-l+1)*v;lazy[k]+=v; //自己要先加好,后代懒得加,打个标记
    return;
}

当我们查询到有懒标记点k时,启动懒标记干活(将懒标记影响下传到子树中,并将懒标记清空)

void pushdown(int k,int l,int r){
    ladd(ls,l,mid,lazy[k]); //给左儿子
    ladd(rs,mid+1,r,lazy[k]); //给右儿子
    lazy[k]=0;
}

pushdown()需要在查询时同步进行!

于是,就可以得新的区间加法代码:

void plu(int k,int l,int r,int x,int y,int v){ //[x,y]区间加v
    if(x<=l&&r<=y) return add(k,l,r,v); //若k对应的区间被x,y包含,打上懒标记就走
    pushdown(k,l,r);
    if(x <= mid) plu(ls,l,mid,x,y,v);
    if(y > mid) plu(rs,mid+1,r,x,y,v);
    return;
} 

区间求和代码:

int ask(int k,int l,int r,int x,int y){
    if(x <= l && r <= y) return s[k];
    pushdown(k,l,r); //唯一不同 
    int res = 0;
    if(x <= mid) res+=ask(ls,l,mid,x,y);
    if(y > mid) res+=ask(rs,mid+1,r,x,y);
   pushup(k,l,r);
return res; }

3.++区间乘?

开两个lazy数组,先乘再加

 

posted @ 2022-02-13 16:07  yinfelix  阅读(44)  评论(0)    收藏  举报