#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a[N];
ll tree[N << 2];
ll tag[N << 2];
ll ls(ll p) { return p << 1; } // 返回左儿子
ll rs(ll p) { return p << 1 | 1; } // 返回右儿子
void push_up(ll p) {
tree[p] = tree[ls(p)] + tree[rs(p)];
}
void build(ll p, ll pl, ll pr) {
tag[p] = 0; // lazy标签
if (pl == pr) { tree[p] = a[pl]; return; } // 这是最底层的叶子
ll mid = pl + pr >> 1;
build(ls(p), pl, mid);
build(rs(p), mid + 1, pr);
push_up(p); // 左右儿子建立好以后可以从下往上传值
}
void addtag(ll p, ll pl, ll pr, ll d) {
// 给节点p打上标签,且跟新tree
tag[p] += d;
tree[p] += d * (pr - pl + 1);
}
void push_down(ll p, ll pl, ll pr) {
// 不能覆盖的时候,把tag传给儿子
if (tag[p]) {
ll mid = pl + pr >> 1;
addtag(ls(p), pl, mid,tag[p]);
addtag(rs(p), mid + 1, pr,tag[p]);
// 自己的tag清零
tag[p] = 0;
}
}
void update(ll l, ll r, ll p, ll pl, ll pr, ll d) {
// 如果完全覆盖
if (l <= pl && pr <= r) {
addtag(p, pl, pr, d); // 直接返回这个节点,他的子树不用修改
return;
}
push_down(p, pl, pr); // 不能覆盖就下传
ll mid = pl + pr >> 1;
if (l <= mid)update(l, r, ls(p), pl, mid, d);
if (r > mid) update(l, r, rs(p), mid + 1, pr,d);
push_up(p); // 跟新
}
ll query(ll l, ll r, ll p, ll pl, ll pr) {
if (pl >= l && r >= pr) return tree[p];
push_down(p, pl, pr); // 不能覆盖,递归子树
ll res = 0;
ll mid = pr + pl >> 1;
if (l <= mid) res += query(l, r, ls(p), pl, mid);
if (r > mid) res += query(l, r, rs(p), mid + 1, pr);
return res;
}
int main() {
ll n, m;
cin >> n >> m;
for (ll i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
while (m--)
{
ll q, l, r, d; cin >> q;
if (q == 1) {
cin >> l >> r >> d;
update(l, r, 1, 1, n, d);
}
else {
cin >> l >> r;
cout << query(l, r, 1, 1, n) << endl;
}
}
return 0;
}
线段树学习
于 2024-04-28 08:45:34 首次发布