#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m;
int a[100001]; // 叶子结点数N
__int64 ans;
struct
{
int l,r;
__int64 sum,add; //__int64
}tree[400000]; //数中所有结点数量大概为 2^2*N 层数logN h=logN+1 或+2 每次插入更新不超过 O(logN)
void build(int l,int r,int i)
{
tree[i].l = l;
tree[i].r = r;
tree[i].add = 0;
if(l == r)
{
tree[i].sum = a[l]; //叶子结点的值=输入数组的值
return ;
}
int mid = (l+r)/2;
build(l,mid,2*i);
build(mid+1,r,2*i+1);
tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;
}
void updata(int l,int r,int add,int i)
{
if(tree[i].l > r || tree[i].r < l)
return ;
if(tree[i].l >= l && tree[i].r <= r)
{
tree[i].sum += (tree[i].r-tree[i].l+1)*add;
tree[i].add += add;
return ; //lazy 只加到分解唯一的子区间
}
if(tree[i].add) //lazy 边更新边维护 为了确保 孩子的 add和 sum正确 必须更新 且更新完后 当前add=0 (更新到最底)的意思
{
tree[2*i].sum += (tree[2*i].r-tree[2*i].l+1)*tree[i].add;
tree[2*i].add += tree[i].add;
tree[2*i+1].sum += (tree[2*i+1].r-tree[2*i+1].l+1)*tree[i].add;
tree[2*i+1].add += tree[i].add;
tree[i].add = 0;
}
updata(l,r,add,2*i);
updata(l,r,add,2*i+1);
tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;
}
void query(int l,int r,int i)
{
if(tree[i].l > r || tree[i].r < l)
return ;
if(tree[i].l >= l && tree[i].r <= r)
{
ans += tree[i].sum;
return ;
}
if(tree[i].add) //lazy 边查询边维护
{
tree[2*i].sum += (tree[2*i].r-tree[2*i].l+1)*tree[i].add;
tree[2*i].add += tree[i].add;
tree[2*i+1].sum += (tree[2*i+1].r-tree[2*i+1].l+1)*tree[i].add;
tree[2*i+1].add += tree[i].add;
tree[i].add = 0;
}
query(l,r,2*i);
query(l,r,2*i+1);
tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;
}
int main()
{
//freopen("in.txt","r",stdin);
int i,x,y,z;
char c;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,n,1);
scanf("%*c");
for(i=1;i<=m;i++)
{
scanf("%c",&c);
if(c == 'Q')
{
scanf("%d%d%*c",&x,&y);
ans = 0;
query(x,y,1);
printf("%I64d\n",ans);
}
else
{
scanf("%d%d%d%*c",&x,&y,&z);
updata(x,y,z,1);
}
}
}
return 0;
}
扒了一线段树代码 注释作分析