题目链接 点击打开链接
以下为参考链接
线段树单点更新和区间更新的区别:
1.每个结点中多了一个add值,代表该结点以下的结点需要增加的值;
2.build函数中,如果在建树的过程中就赋值给num,那么在建完树之后不要忘记pushup,因为此时只是叶子结点有值,上面的值都为空;这个在区间更新中很常用,因为区间更新中如果输入一个值,然后更新一个值,这样会很麻烦,会耗费更多的时间;
3.update函数中,区间更新多了一个pushdown函数,并且更新sum和add值的判断条件是树中结点的l~r和要更新的区间的l~r相等,此时sum加的值是整个区间的长度*要更新的值,然后add值记录后面每个结点需要加上的值,即:c;
4.pushdown函数最后不要忘了将延时标记add清零;
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int inf=1<<20;
const int M = 1e5+5;
long long sum[M<<2],add[M<<2];//重点 lazy标记:add[rt] 代表 rt以下的节点所要增加的值
struct node{
int l,r;
int mid()
{
return (l+r)>>1;
}
}tree[M<<2];
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
tree[rt].l=l;
tree[rt].r=r;
add[rt]=0;//
if(l==r)//leaf
{
scanf("%I64d",&sum[rt]);
return;
}
int m=tree[rt].mid();
build(lson);
build(rson);
pushup(rt);
}
void PushDown(int rt,int len)//区间rt的长度为len
{
if(add[rt])
{
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];//往下标记
sum[rt<<1]+=add[rt]*(len-(len/2));
sum[rt<<1|1]+=add[rt]*(len/2);
add[rt]=0;//更新后还原add[rt]
}
}
void update(int c,int l,int r,int rt) // 区间l,r中的每个元素增加c
{
if(tree[rt].l==l&&tree[rt].r==r) //lazy思想
{
add[rt]+=c;
sum[rt]+=c*(r-l+1);
return;//暂时不更新子节点的值
//在某部分update操作的时候需要用到那部分没有更新的节点的值的时候,
//这里可能有点绕口。这时就掉用PushDown()函数更新子节点的数值。
}
if(tree[rt].l==tree[rt].r)
return;
PushDown(rt,tree[rt].r-tree[rt].l+1);// 要分解区间时(要用到子区间)
//更新子区间(把以前还没更新的更新了)
int m=tree[rt].mid();
//更新查询要区间l,r所在的那一段
if(r<=m)//在该节点的左边
{
update(c,l,r,rt<<1);
}
else if(l>m)
{
update(c,l,r,rt<<1|1);
}
else//横跨中点 继续分解
{
update(c,l,m,rt<<1);
update(c,m+1,r,rt<<1|1);
}
pushup(rt);
}
long long query(int l,int r,int rt)
{
if(l==tree[rt].l&&r==tree[rt].r)//完全包含
{
return sum[rt];
}
//要用到子区间
PushDown(rt,tree[rt].r-tree[rt].l+1);
int m=tree[rt].mid();
long long res=0;
//分解区间
if(r<=m)
{
res+=query(l,r,rt<<1);
}
else if(l>m)//所查询区间在右半段
{
res+=query(l,r,rt<<1|1);
}
else//l<m<r<tree[rt].r
{
res+=query(l,m,rt<<1);
res+=query(m+1,r,rt<<1|1);
}
return res;
}
int main()
{
int n,q;
cin>>n>>q;
build(1,n,1);
while(q--)
{
char c;
cin>>c;
if(c=='C')
{
int a,b,c;
cin>>a>>b>>c;
update(c,a,b,1);
}
if(c=='Q')
{
int l,r;
cin>>l>>r;
cout<<query(l,r,1)<<endl;
}
}
return 0;
}