数据结构的半夜——线段树学习笔记1 (3)

我为大家大致翻译一下题干,意为需维护一个长度为N的int数组A,相对应的Q组询问,有两种操作,C l r k 意为将[l,r]区间每个数加上k,Q l r,询问[l,r]的区间和。

这便是区间修改问题。

这里要使用一种标记数组,lazytag

lazytag存储在父节点上,为该区间总共需要加上的数值,所以为了维护线段树,每次向下层递归前,都要下传lazytag

我们先来看一下区间修改函数

inline void update(ll l,/*当前区间左端点*/ ll r,/*当前区间右端点*/ ll x,/*所询问区间左端点*/ ll y,/*所询问区间右端点*/ ll th, ll k) { if(x<=l && r<=y)//若完全包含,便把值记录在tag上 { add(l,r,th,k); return; } pushdown(l,r,th);//递归前下传标记 ll mid=l+r >>1; if(x<=mid) update(l,mid,x,y,lson,k); if(y>mid) update(mid+1,r,x,y,rson,k); pushup(th); }

add函数

inline void add(ll l,ll r,ll th,ll k) { tag[th]+=k;//tag更新 sum[th]+=(r-l+1)*k;//自身维护 return; }

这里有个pushdown函数,是pushup函数的反向操作

inline void pushdown(ll l,ll r,ll th) { if(tag[th]==0) return;//若tag为0则返回 ll mid=l+r >>1; add(l,mid,lson,tag[th]);//下传标记 add(mid+1,r,rson,tag[th]); tag[th]=0;//别忘了清零 }

这里为什么只下传一层呢:因为正如之前所说,每次向下递归前都要下传标记,所以到下层标记自然会下传

所以这里的询问有了些小小的变化

ll query(ll l,ll r,ll x,ll y,ll th) { if(x<=l && r<=y) { return sum[th]; } ll mid=l+r >>1; ll res=0; pushdown(l,r,th); if(x<=mid) res+=query(l,mid,x,y,lson); if(y>mid) res+=query(mid+1,r,x,y,rson); return res; }

然而为什么要用longlong呢,题中明明说是int数组

这时我们再通读题面,会发现一行话

The sums may exceed the range of 32-bit integers.

区间和可能会超过32位int类型

这便是要用longlong的原因

标程

#include<cstdio> #include<cstring> #include<iostream> #define lson th<<1 #define rson th<<1|1 #define maxn 100005 typedef long long ll; using namespace std; ll sum[maxn*4]; ll a[maxn]; ll n,m; ll tag[maxn*4]; inline void add(ll l,ll r,ll th,ll k) { tag[th]+=k; sum[th]+=(r-l+1)*k; return; } inline void pushup(ll th) { sum[th]=sum[lson]+sum[rson]; return; } inline void pushdown(ll l,ll r,ll th) { if(tag[th]==0) return; ll mid=l+r >>1; add(l,mid,lson,tag[th]); add(mid+1,r,rson,tag[th]); tag[th]=0; } inline void build(ll l,ll r,ll th) { if(l==r) { sum[th]=a[l]; return; } ll mid=l+r >> 1; build(l,mid,lson); build(mid+1,r,rson); pushup(th); } inline void update(ll l,ll r,ll x,ll y,ll th,ll k) { if(x<=l && r<=y) { add(l,r,th,k); return; } pushdown(l,r,th); ll mid=l+r >>1; if(x<=mid) update(l,mid,x,y,lson,k); if(y>mid) update(mid+1,r,x,y,rson,k); pushup(th); } ll query(ll l,ll r,ll x,ll y,ll th) { if(x<=l && r<=y) { return sum[th]; } ll mid=l+r >>1; ll res=0; pushdown(l,r,th); if(x<=mid) res+=query(l,mid,x,y,lson); if(y>mid) res+=query(mid+1,r,x,y,rson); return res; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } build(1,n,1); while(m--) { char str[5]; scanf("%s",str); if(str[0]=='C') { ll x,y,k; scanf("%lld%lld%lld",&x,&y,&k); update(1,n,x,y,1,k); } else{ ll x,y; scanf("%lld %lld",&x,&y); printf("%lld\n",query(1,n,x,y,1)); } } }

理解了之后代码难度并不是非常大,毕竟只是最最基础的应用而已。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpyfyj.html