(简要笔记,仅供参考,可能存在瑕疵或者不正确的地方,望指正)
(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;
}