#include <bits/stdc++.h>
#define int long long
const int maxn=1e5+5;
using namespace std;
typedef struct tree
{
int l,r,sum,add,len;//l,r区间左右界,sum是维护的区间和,add是懒惰标记,len是区间长度
} tr;
tr tree[maxn<<2];
void pushup(int p)//上传更新维护根结点的值
{
tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mod;
}
void pushdown(int p)//下传懒惰标记更新子区间的值
{
if(!tree[p].add)
return;//如果没有懒惰标记就不用下传了
//子树的sum值=原来的sum值+其根结点的懒惰标记记录的每个数要加的值*该子树所示区间的长度
//(懒惰标记记录的每个数要加的值*该子树所示区间的长度)即该区间要加的总的值
tree[p<<1].sum=(tree[p<<1].sum+tree[p<<1].len*tree[p].add)%mod;
//子树的标记值=原来的标记值+其根结点下传的标记值
tree[p<<1].add=(tree[p<<1].add+tree[p].add)%mod;
tree[p<<1|1].sum=(tree[p<<1|1].sum+tree[p<<1|1].len*tree[p].add)%mod;
tree[p<<1|1].add=(tree[p<<1|1].add+tree[p].add)%mod;
tree[p].add=0;//懒惰标记下传给子树后要清除(防止下次询问时再加上此标记的值,因为下传完之后该加的都加了)
}
void build(int p,int l,int r)
{
tree[p].l=l;
tree[p].r=r;
tree[p].len=tree[p].r-tree[p].l+1;
if(l==r)
{
tree[p].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r,int x)
{
if(tree[p].l>=l&&tree[p].r<=r)//这里因为要用懒惰标记所以找涉及的区间修改就行了
{
tree[p].sum+=tree[p].len*x;//该结点sum值=原来的sum值+其区间长度*该区间每个数要加的值
tree[p].add+=x;
return;
}
pushdown(p);//当前区间不在所找范围要遍历其子区间时要先把懒惰标记下传给其子区间
int mid=(tree[p].l+tree[p].r)>>1;
if(l<=mid)
modify(p<<1,l,r,x);
if(r>mid)
modify(p<<1|1,l,r,x);
pushup(p);
}
int query(int p,int l,int r)
{
if(tree[p].l>=l&&tree[p].r<=r)
{
return tree[p].sum;
}
pushdown(p);//同上,当前区间不在所找范围要遍历其子区间时要先把懒惰标记下传给其子区间
int mid=(tree[p].l+tree[p].r)>>1;
int ans=0;
if(l<=mid)
ans+=query(p<<1,l,r)%mod;
if(r>mid)
ans+=query(p<<1|1,l,r)%mod;
return ans%mod;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
build(1,1,n);
return 0;
}
线段树的区间修改模板(含懒惰标记)
猜你喜欢
转载自blog.csdn.net/Mr_Kingk/article/details/99590004
今日推荐
周排行