每个节点运用结构体来存储信息
struct node
{
ll l,r,w,f;//l 节点的左端点。r 节点的右端点。w 为节点的和。f 为懒惰标记
} tree[6*1000001];
建树
void build(ll l,ll r,ll k)
{
tree[k].l=l;//存储左端点
tree[k].r=r;//存储右端点
if(l==r)
{
scanf("%lld",&tree[k].w);
return ;
}
ll m=(l+r)/2;
build(l,m,2*k);//建立左子树
build(m+1,r,2*k+1);//建立右子树
tree[k].w=tree[2*k].w+tree[2*k+1].w;
}
单点查询
void sum(int k)
{
if(tree[k].l==tree[k].r)
{
p=tree[k].w;
return ;
}
int m=(tree[k].l+tree[k].r)/2;
if(tree[k].f)
down(k);
if(x<=m)
sum(2*k);
else
sum(2*k+1);
}
单点修改
void add(ll k)
{
if(tree[k].l==tree[k].r)
{
tree[k].w+=y;
return ;
}
ll m=(tree[k].l+tree[k].r)/2;
if(tree[k].f) down(k);//若代码没有使用懒惰标记,可以不用加
if(x<=m)
add(2*k);
else
add(2*k+1);
tree[k].w=tree[2*k].w+tree[2*k+1].w;
}
区间修改
void add(ll k)
{
if(x<=tree[k].l&&tree[k].r<=y)
{
tree[k].w+=(tree[k].r-tree[k].l+1)*z;//更新节点
tree[k].f+=z;//更新懒惰数组
return ;
}
ll m=(tree[k].l+tree[k].r)/2;
if(tree[k].f) down(k);//向下传递懒惰标记
if(x<=m)
add(2*k);
if(y>m)
add(2*k+1);
tree[k].w=tree[2*k].w+tree[2*k+1].w;//更新父节点
}
区间查询
void sum(ll k)
{
if(tree[k].l>=x&&tree[k].r<=y)
{
ans+=tree[k].w;
return ;
}
if(tree[k].f)
down(k);
ll m=(tree[k].l+tree[k].r)/2;
if(m>=x)
sum(2*k);
if(y>m)
sum(2*k+1);
}
懒惰数组
void down(ll k)
{
tree[2*k].f+=tree[k].f;
tree[2*k+1].f+=tree[k].f;//更新子节点的懒惰数组
tree[2*k].w+=(tree[2*k].r-tree[2*k].l+1)*tree[k].f;
tree[2*k+1].w+=(tree[2*k+1].r-tree[2*k+1].l+1)*tree[k].f;//更新节点的和
tree[k].f=0;//将节点懒惰标记归零。
}