功能
在区间上进行信息统计,需注意信息在节点之间传递的属性是什么,根据属性的不同来改变写法
简写
#define ul u * 2
#define ur u * 2 + 1
#define l(u) tr[u].l
#define r(u) tr[u].r
#define dat(u) tr[u].dat
#define lay(u) tr[u].delay
存储( 下标从 1 开始 )
struct node
{
int l, r; //当前节点的左右区间
int delay; //延迟标记( 只有涉及区间修改时才需 )
int dat; //信息1
}tr[N * 4]; //节点个数的四倍大小
递归后上捞节点信息( 创建 修改 )
void pushup( int u ) //两个子节点递归完成后更新父节点
{
tr[u].dat = tr[u * 2].dat + tr[u * 2 + 1].dat;
}
递归前下传延迟标记( 区间修改 查询 )
void pushdown( int u )
{
//左右子节点分别加上父节点的延迟标记
tr[u * 2].delay += tr[u].delay; //和延迟标记对区间所带来的影响
tr[u * 2].dat += ( tr[u * 2].r - tr[u * 2].l + 1) * tr[u].delay;
tr[u * 2 + 1].delay += tr[u].delay;
tr[u * 2 + 1].dat += ( tr[u * 2 + 1].r - tr[u * 2 + 1].l + 1) * tr[u].delay;
tr[u].delay = 0; //节点的延迟标记清零
}
创建
void build( int u, int l, int r ) //当前正在创建区间为[l ~ r]的第u个节点
{
tr[u] = { l, r }; //表明节点的左右区间
tr[u].delay = 0; //和延迟标记
if( l == r )
tr[u].dat = a[l]; //如果是叶子节点则填充信息
else
{ //如果不是叶子节点则递归左右节点
int mid = l + r >> 1; //拆分
build( u * 2, l, mid ); //递归左子节点
build( u * 2 + 1, mid + 1, r ); //递归右子节点
pushup( u ); //上捞节点信息
}
}
单点修改
int modify( int u, int x, int y ) //把编号为 x 的数修改为 y
{
if( tr[u].l == x && tr[u].r == x ) //如果是叶子节点则修改信息
tr[u].dat = y;
else //如果不是叶子节点则递归左右节点
{
int mid = tr[u].l + tr[u].r >> 1; //拆分
if( x <= mid )
modify( u * 2, x, y ); //递归左子节点
else
modify( u * 2 + 1, x, y ); //递归右子节点
pushup( u ); //上捞节点信息
}
}
区间修改
void modify(int u, int l, int r, int d) //给区间 [l ~ r] 施加影响 d
{
if ( l <= tr[u].l && tr[u].r <= r) //如果完全覆盖
{
tr[u].dat += ( tr[u].r - tr[u].l + 1 ) * d;//更新节点信息
tr[u].delay += d; //给节点打延迟标记
}
else //如果不完全覆盖
{
pushdown( u ); //下传延迟标记
int mid = tr[u].l + tr[u].r >> 1; //拆分
if ( l <= mid )
modify( u * 2, l, r, d ); //递归左子节点
if ( mid < r )
modify( u * 2 + 1, l, r, d ); //递归右子节点
pushup( u ); //上捞节点信息
}
}
查询
int query( int u, int l, int r ) //l r 相同则为查询点
{
if( l <= tr[u].l && tr[u].r <= r ) //如果完全覆盖
return tr[u].dat; //返回查询结果备用
int res = 0; //定义查询初值
pushdown( u ); //下传延迟标记
int mid = tr[u].l + tr[u].r >> 1; //拆分
if( l <= mid )
res = ...query( u * 2, l, r ); //递归查询左子节点
if( mid < r )
res = ...query(u * 2 + 1, l, r ); //递归查询右子节点
return res; //返回查询结果
}