整理一下线段树的模板。
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
using namespace std;
#define lson i << 1
#define rson i << 1 | 1
#define ll long long
const int MAX_N = 100005;//题目描述n 1e5
int a[MAX_N];//存放需要放进树的数据
//定义树的节点
struct node
{
int l, r;//节点表示范围
ll lazy;//lazy跟新延迟标记
//sum节点属性
ll sum;
inline int len()//管辖区间内元素的数目
{
return r - l + 1;
}
//针对区间和问题的update
inline void update(ll val)
{
lazy += val;
//对父亲节点+个数*val,不查询子叶节点就不下放
sum += 1LL * len() * val;//1LL防止int溢出,转为ll
}
}tree[MAX_N << 2];//x<<2 = x*2^2
/**回溯跟新**/
void push_up(int i)
{
tree[i].sum = tree[lson].sum + tree[rson].sum;
}
/**下放标记**/
void push_down(int i)//i号节点
{
ll lazy = tree[i].lazy;
if (lazy == 0)
return;
tree[lson].update(lazy);
tree[rson].update(lazy);
tree[i].lazy = 0;
}
/**建立线段树**/
void build(int i, int l, int r)//1, 1, n
{
tree[i].l = l;
tree[i].r = r;
tree[i].lazy = tree[i].sum = 0;
if (l == r)
{
tree[i].sum = a[l];
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
push_up(i);//建立的过程中顺带区间统计
}
/**更新线段树**/
void update(int i, int l, int r, int val)//1, l, r, +c
{
//缩到目标范围时 ,对父亲节点调用struct内部的update函数
if (tree[i].l == l && tree[i].r == r)
{
tree[i].update(val);
return;
}
//走到这里说明还没到达合适的目标范围
push_down(i);//lazy下放
int mid = (tree[i].l + tree[i].r) >> 1;
if (r <= mid)//目标右边界比当前mid还小,必然往左找
update(lson, l, r, val);
else if (l > mid)//目标左边界比当前mid还大,必然往右找
update(rson, l, r, val);
else//l <= mid <= r
{
update(lson, l, mid, val);
update(rson, mid + 1, r, val);
}
//如果是刚刚好的情况,那么i是不用更新的(直接update)
//但是对于上面的分支,可能这个父亲节点的i不是恰好统治这个范围
//所以就要逐层更新上去
push_up(i);
}
/**查询**/
ll query(int i, int l, int r)
{
if (tree[i].l == l && tree[i].r == r)//缩到目标区间
{
return tree[i].sum;
}
//因为要查询,所以下放lazy
push_down(i);
int mid = (tree[i].l + tree[i].r) >> 1;
if (r <= mid)
return query(lson, l, r);
else if (l > mid)
return query(rson, l, r);
else
return query(lson, l, mid) + query(rson, mid + 1, r);
}
///
OFF MUBAN//
//
int main()
{
//假如有通过1/0或字母指定操作operation
char op[10];
int N, //数字个数
Q; //询问/操作个数
scanf("%d %d", &N, &Q);//N
//读入数据
for (int i = 1; i <= N; ++i)
scanf("%d", &a[i]);
//建树
build(1, 1, N);
//进行操作
for (int i = 1; i <= Q; ++i)
{
scanf("%s", op);
if (op[0] == 'Q')//查询区间和
{
int l, r;
scanf("%d %d", &l, &r);
printf("%lld\n", query(1, l, r));
}
else//‘C’ 区间内都+val
{
int l, r, val;
scanf("%d %d %d", &l, &r, &val);
update(1, l, r, val);
}
}
return 0;
}