0
点赞
收藏
分享

微信扫一扫

线段树简单笔记

吴陆奇 2022-02-03 阅读 47

(简要笔记,仅供参考,可能存在瑕疵或者不正确的地方,望指正)

(1)维护区间信息(比如区间和,区间最大值等)。

1组成

(1)node tree[4*N];

(2)void push_up(int p)//将两个子数的信息合并。

{

tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;//p<<1==p*2;p<<1|1==p*2+1。

}

单点更新 区间查询

(3)struct node{

int r;//右端点

int l;//左端点

int sum;//包含的信息,这里是和。

}

(4)void build(int l,r,p);

{

tree[p].l=l;

tree[p].r=r;

int mid=(l+r)/2;

if(l==r)

{

tree[p].sum=a[r];//左边界和有边界相等的树的底部,是给定数组的下标为r的

单个数,递归边界。

}

build(l,mid,p<<1);//左儿子

build(mid+1,r,p<<1|1);//右儿子

push_up(p);//合并

}

(5)void update(int pos,int v,int p)

{

int l=tree[p].l,r=tree[p].r;

int mid=(r+l)/2;

if(l==r)//递归边界

{

tree[p].sum=v;

return;

}

if(pos<=mid)

update(pos,v,p<<1);//如果pos在左边,向左儿子遍历。

else

update(pos,v,p<<1|1);//如果pos在右边,向右儿子遍历。

push_up(p);//合并。

}

(6)int query(int ql,int qr,int p)//求区间和

{

int l=tree[p].l,r=tree[p].r;

int mid=(l+r)/2;

if(ql<=l&&qr>=r)//如果当前区间完全包括在要查询的区间中,直接返回信息

return tree[p].sum;

int ans=0;

if(ql<=mid)//如果查询区间和左儿子有交集,就访问左儿子

ans+=query(ql,qr,p<<1)

if(qr>mid)//如果查询区间和右儿子有交集,就访问右儿子

ans+=query(ql,qr,p<<|1);

return ans;

}

区间修改 区间查询

(7)struct node{

int l,r,sum;

int lazy;//lazy标记,用于存储更新内容

}

(8)void push_down(int p)

{

if(!tree[p].lazy)//如果没有lazy标记,那么直接结束。

return;

tree[p<<1].lazy+=tree[p].lazy;

tree[p<<1|1].lazy+=tree[p].lazy;//在左儿子和右儿子上都加lazy标记。

tree[p<<1].sum+=(tree[p<<1].r-tree[p<<1].l+1)*tree[p<<1].lazy;//更新左右儿子的信息

tree[p<<1|1].sum+=(tree[p<<1|1].r-tree[p<<1|1].l+1)*tree[p<<1|1].lazy;

tree[p].lazy=0;//清除lazy标记。

}

(9)void build(int l,int r,int p)//建树

{

tree[p].l=l;tree[p].r=r;tree[p].lazy=0;

int mid=(l+r)/2;

if(l==r){

tree[p].sum=a[l];//递归边界

}

build(l,mid,p<<1)//创建左儿子

build(mid+1,r,p<<1|1)//创建右儿子

push_up(p);//合并

return ;

}

(10)void update(int upl,int upr,int v,int p)//区间修改

{

int l=tree[p].l,r=tree[p].r;

int mid=(l+r)/2;

if(upl<=l&&r<=upr)//如果当前区间包括在所要查询的区间内,直接更新信息

{

tree[p].sum+=v*(r-l+1);

tree[p].lazy+=v;

return;

}

if(upl<=mid)//如果和左儿子有交集,遍历左儿子

update(upl,upr,v,p<<1);

if(upr>mid)//如果和右儿子有交集,遍历右儿子

update(upl,upr,v,p<<1|1);

push_up(p);//合并信息

}

int query(int ql,int qr,int p)

{

int l=tree[p].l,r=tree[p].r;

int mid=(l+r)/2;

if(ql<=l&&r<=qr)//如果当前区间完全包含在查询区间内,直接返回节点信息。

return tree[p].sum;

push_down(p)//下传节点信息

int ans;

if(ql<=mid)

ans+=query(ql,qr,p<<1);//如果和左儿子有交集,遍历左儿子。

if(qr>mid)

ans+=query(ql,qr,p<<1|1);//如果和右儿子有交集,遍历右儿子。

return ans;

}

举报

相关推荐

0 条评论