参考博客 http://blog.youkuaiyun.com/metalseed/article/details/8039326
持续更新。。。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xhRgdjCd-1613976863463)(https://img-blog.youkuaiyun.com/20160726111332454)]
区间存储在数组中的下标对应为
1
2 3
4 5 6 7
8 9 10 11 12 13 14 15
四部分
- 单点更新:
根据题目的要求编写自己的Pushup,Query
这种问题的实质就是每次递归更新两个子节点,然后调用PushUp更新父节点。
int a[50000<<2];
void PushUp(int rt)
{
a[rt]=a[rt<<1]+a[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
RI(a[rt]);
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
PushUp(rt);
}
void update(int l,int r, int rt,int poi,int add)
{
if(l==r)
{
a[rt]+=add;
return ;
}
int m=(l+r)>>1;
if(poi<=m) update(l,m,rt<<1,poi,add);
if(poi>m) update(m+1,r,rt<<1|1,poi,add);
PushUp(rt);
}
LL query(int l,int r,int rt,int L,int R)
{
if(L<=l&&r<=R) return a[rt];
int m=(l+r)>>1;
LL ans=0;
if(m>=L) ans+=query(l,m,rt<<1,L,R);
if(m<R) ans+=query(m+1,r,rt<<1|1,L,R);
return ans;
}
2.区间更新
add表示延迟标记,表示其对应的子区间中的值要加上add,这样每次更新的时候就不必全部相加。
注意update区间的时候要加上PushDown,不然可能更新会导致子节点对应父节点的值计算错误。
LL summ[100000<<2];
int add[100000<<2];
void PushUp(int rt)
{
summ[rt]=summ[rt<<1]+summ[rt<<1|1];
}
void Pushdown(int rt,int m)
{
if(add[rt])
{
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
summ[rt<<1]+=add[rt]*(LL)(m-(m>>1));
summ[rt<<1|1]+=add[rt]*(LL)(m>>1);
add[rt]=0;
}
}
void build(int l,int r,int rt)
{
add[rt]=0;
if(l==r)
{
scanf("%I64d",&summ[rt]);
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
PushUp(rt);
}
void update(int l,int r, int rt,int L,int R,int c)
{
if(L<=l&&r<=R)
{
summ[rt]+=(LL)(r-l+1)*(LL)c;
add[rt]+=c;
return ;
}
Pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m) update(l,m,rt<<1,L,R,c);
if(R>m) update(m+1,r,rt<<1|1,L,R,c);
PushUp(rt);
}
LL query(int l,int r,int rt,int L,int R)
{
if(L<=l&&r<=R) return summ[rt];
Pushdown(rt,r-l+1);
int m=(l+r)>>1;
LL ans=0;
if(m>=L) ans+=query(l,m,rt<<1,L,R);
if(m<R) ans+=query(m+1,r,rt<<1|1,L,R);
return ans;
}