题目分析
关于 p u s h d o w n pushdown pushdown操作,是懒标记( t a g tag tag)下放和子节点信息更新的操作,其目的是维护线段树的父节点与子节点之间的关系,在每次更新( u p d a t e update update)和查询( q u e r y query query)子节点操作前都要 p u s h d o w n pushdown pushdown,以保证更新和查询子节点时子节点的值是正确的. 否则,所有的信息都会记录在根节点,导致子节点无法被更新.
同理我们有 p u s h u p pushup pushup操作,是子节点更新完毕后回溯更新父节点的过程. 与 p u s h d o w n pushdown pushdown不同的是,此时要更新的只有父节点的值 a n s ans ans而没有 t a g tag tag.
void update(ll p,ll l,ll r,ll ql,ll qr,ll k){
if(ql<=l&&r<=qr){
ans[p]+=(r-l+1)*k;
tag[p]+=k;
return ;
}
ll mid=(l+r)>>1;
push_down(p,l,r);
if(ql<=mid)update(ls(p),l,mid,ql,qr,k);
if(mid<qr)update(rs(p),mid+1,r,ql,qr,k);
ans[p]=ans[ls(p)]+ans[rs(p)];//更新父节点
}
注意 u p d a t e update update中的 p u s h d o w n pushdown pushdown操作,它维护了子节点的信息正确性.
我不会告诉你我就是因为一开始没有它板子才10分的
程序实现
#include<bits/stdc++.h>
#define ll long long
#define maxn 100010
using namespace std;
int n,m;
ll a[maxn],ans[maxn<<2],tag[maxn<<2];
ll ls(ll x){return x<<1;}
ll rs(ll x){return x<<1|1;}
void build(ll p,ll l,ll r){
if(l==r){ans[p]=a[l];return ;}
ll mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
ans[p]=ans[ls(p)]+ans[rs(p)];//pushup操作,更新父节点
}
void push_down(ll p,ll l,ll r){
ll mid=(l+r)>>1;
ans[ls(p)]+=tag[p]*(mid-l+1);
ans[rs(p)]+=tag[p]*(r-mid);
tag[ls(p)]+=tag[p];
tag[rs(p)]+=tag[p];//以上更新子节点信息
tag[p]=0;//懒标记全部下放
}
void update(ll p,ll l,ll r,ll ql,ll qr,ll k){
if(ql<=l&&r<=qr){
ans[p]+=(r-l+1)*k;
tag[p]+=k;
return ;
}
ll mid=(l+r)>>1;
push_down(p,l,r);
if(ql<=mid)update(ls(p),l,mid,ql,qr,k);
if(mid<qr)update(rs(p),mid+1,r,ql,qr,k);
ans[p]=ans[ls(p)]+ans[rs(p)];//更新父节点
}
ll query(ll p,ll l,ll r,ll ql,ll qr){
if(ql<=l&&r<=qr){return ans[p];}
ll ret=0;
ll mid=(l+r)>>1;
push_down(p,l,r);
if(ql<=mid)ret+=query(ls(p),l,mid,ql,qr);
if(mid<qr)ret+=query(rs(p),mid+1,r,ql,qr);
return ret;
}
int main(){
ll a1,b,c,d;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build(1,1,n);
for(int i=1;i<=m;i++){
scanf("%lld",&a1);
if(a1==1){
scanf("%lld%lld%lld",&b,&c,&d);
update(1,1,n,b,c,d);
}
else {
scanf("%lld%lld",&b,&c);
printf("%lld\n",query(1,1,n,b,c));
}
}
return 0;
}