目录
题目描述:
维护父节点的值:
建树:
区间修改计算函数:
下放lazy值的函数:
区间修改函数:
区间查询函数:
完整代码:
如题,已知一个数列,你需要进行下面两种操作:
输入格式:
第一行包含两个整数 n, m,分别表示该数列数字的个数和操作的总个数。
第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 m 行每行包含 3 或 4 个整数,表示一个操作,具体如下:
1 x y k
:将区间 [x,y] 内每个数加上 k。2 x y
:输出区间 [x,y] 内每个数的和。输出格式:
输出包含若干行整数,即为所有操作 2 的结果。
//父节点的值为两子节点的值之和
void pushup(ll pos) {
sum[pos] = sum[pos * 2] + sum[pos * 2 + 1];
}
//sum数组为子节点的和
void build(ll pos, ll l, ll r) {
//初始化lazy数组
lazy[pos] = 0;
//若该节点为叶子节点,则sum中存储的为该节点的值
if(l == r) {
sum[pos] = a[l];
return;
}
//若不为叶子节点,则递归调用函数,直至叶子节点
ll mid = (l + r) / 2;
build(pos * 2, l, mid);
build(pos * 2 + 1, mid + 1, r);
//若该节点不为叶子节点,则更新该节点的值
//使得该点为两子节点的和
pushup(pos);
}
//lazy保存某个节点及其子节点是否被修改过
//若为零,则未被修改
//若不为零,则在该范围内的每个叶子节点均需加上lazy的值
//(此时还未修改,只是存储在这,需要等到lazy从不为零的值变为零,才修改了这段区间的值)
void f(ll pos, ll l, ll r, ll num) {
//将lazy下放,因为可能存在之前的lazy未被使用
//故需要进行加法计算,而不是直接赋值
lazy[pos] += num;
//该节点可能不为叶子节点,长度不一定为1,故应加上lazy的值乘以长度
//修改了sum数组的值,但不一定修改了每个节点的值
sum[pos] += num * (r - l + 1);
}
void pushdown(ll pos, ll l, ll r) {
//以该点为根节点,保证每个节点都能被修改到
ll mid = (l + r) / 2;
f(pos * 2, l, mid, lazy[pos]);
f(pos * 2 + 1, mid + 1, r, lazy[pos]);
//使用lazy数组将子节点的值更新后,需将lazy置零,避免再次使用
lazy[pos] = 0;
}
void update(ll nl, ll nr, ll l, ll r, ll pos, ll num) {
//若需要改变的范围完全覆盖此时查询的范围
if(nl <= l && r <= nr) {
//将sum数组及时更新
sum[pos] += num * (r - l + 1);
//先不着急改变左右子节点的值
//用lazy数组存储该节点修改的值
lazy[pos] += num;
return;
}
//将lazy下放
pushdown(pos, l, r);
ll mid = (l + r) / 2;
//若与左子节点有交集,则向左进行判断
if(nl <= mid)
update(nl, nr, l, mid, pos * 2, num);
//同理,若与右子节点有交集,则向右进行判断
if(nr > mid)
update(nl, nr, mid + 1, r, pos * 2 + 1, num);
//该点的子节点可能已经改变,故更新该节点的值
pushup(pos);
}
ll query(ll nl, ll nr, ll l, ll r, ll pos) {
ll res = 0;
//若查询的范围完全覆盖此时遍历的范围
//若查询的范围合法,则该返回值是为了递归调用做准备
if(nl <= l && r <= nr)
return sum[pos];
ll mid = (l + r) / 2;
//使用之前存储的lazy
pushdown(pos, l, r);
if(nl <= mid)
res += query(nl, nr, l, mid, pos * 2);
if(nr > mid)
res += query(nl, nr, mid + 1, r, pos * 2 + 1);
return res;
}
#include
using namespace std;
#define ll long long
const int N = 1e5 + 10;
ll n, m, a[N], flag, x, y, k, sum[N * 4], lazy[N * 4];
void pushup(ll pos) {
sum[pos] = sum[pos * 2] + sum[pos * 2 + 1];
}
void build(ll pos, ll l, ll r) {
lazy[pos] = 0;
if(l == r) {
sum[pos] = a[l];
return;
}
ll mid = (l + r) / 2;
build(pos * 2, l, mid);
build(pos * 2 + 1, mid + 1, r);
pushup(pos);
}
void f(ll pos, ll l, ll r, ll num) {
lazy[pos] += num;
sum[pos] += num * (r - l + 1);
}
void pushdown(ll pos, ll l, ll r) {
ll mid = (l + r) / 2;
f(pos * 2, l, mid, lazy[pos]);
f(pos * 2 + 1, mid + 1, r, lazy[pos]);
lazy[pos] = 0;
}
void update(ll nl, ll nr, ll l, ll r, ll pos, ll num) {
if(nl <= l && r <= nr) {
sum[pos] += num * (r - l + 1);
lazy[pos] += num;
return;
}
pushdown(pos, l, r);
ll mid = (l + r) / 2;
if(nl <= mid)
update(nl, nr, l, mid, pos * 2, num);
if(nr > mid)
update(nl, nr, mid + 1, r, pos * 2 + 1, num);
pushup(pos);
}
ll query(ll nl, ll nr, ll l, ll r, ll pos) {
ll res = 0;
if(nl <= l && r <= nr)
return sum[pos];
ll mid = (l + r) / 2;
pushdown(pos, l, r);
if(nl <= mid)
res += query(nl, nr, l, mid, pos * 2);
if(nr > mid)
res += query(nl, nr, mid + 1, r, pos * 2 + 1);
return res;
}
int main() {
scanf("%lld %lld", &n, &m);
for(ll i = 1; i <= n; ++i)
scanf("%lld", &a[i]);
//从最开始构建树
build(1, 1, n);
while(m--) {
scanf("%lld", &flag);
if(flag == 1) {
scanf("%lld %lld %lld", &x, &y, &k);
update(x, y, 1, n, 1, k);
}
else {
scanf("%lld %lld", &x, &y);
printf("%lld\n", query(x, y, 1, n, 1));
}
}
return 0;
}