洛谷 P3372 【模板】线段树 1

P3372 【模板】线段树 1

带懒标记的线段树

学习线段树的第三天,懒标记写的还很不熟练

模板题不需要思路,直接上代码:

#include <iostream>
#include <algorithm>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, m;
ll a[N];

struct Node {
    int l, r;
    ll sum, lazy;
}st[N * 4];

void pushup (int u) {
    st[u].sum = st[u << 1].sum + st[u << 1 | 1].sum;
}

void pushdown (int x) {
    auto &u = st[x], &l = st[x << 1], &r = st[x << 1 | 1];
    if (u.lazy) {
        l.lazy += u.lazy, l.sum += (ll)(l.r - l.l + 1) * u.lazy;
        r.lazy += u.lazy, r.sum += (ll)(r.r - r.l + 1) * u.lazy;
        u.lazy = 0;
    }//这里还很不熟练,特别是区间和
    
}

void build (int u, int l, int r) {
    if (l == r) {
        st[u] =  {l, r, a[r], 0}; //不需要往下传,所以pushdown 0
        return;
    }

    st[u] = {l, r};
    int mid = l + r >> 1;
    build (u << 1, l, mid);
    build (u << 1 | 1, mid + 1, r);
    pushup (u);
}

void modify (int u, int l, int r, int v) {
    if (st[u].l >= l && st[u].r <= r){
        st[u].sum += (ll) (st[u].r - st[u].l + 1) * v;
        st[u].lazy += v;;
        return;
    }
        
    pushdown (u);
    int mid = st[u].l + st[u].r >> 1;
    if (l <= mid)
        modify (u << 1, l, r, v);
    if (r > mid)
        modify (u << 1 | 1, l, r, v);
    pushup (u);
}

ll query (int u, int l, int r) {
    if (st[u].l >= l && st[u].r <= r)
        return st[u].sum;

    pushdown (u);
    ll res = 0;
    int mid = st[u].l + st[u].r >> 1;
    if (l <= mid)
        res += query (u << 1, l, r);
    if (r > mid)
        res += query (u << 1 | 1, l, r);
    return res;
}

int main () {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++)
        cin >> a[i];

    build (1, 1, n);

    while (m --) {
        int op, x, y, k;
        cin >> op >> x >> y;
        if (op == 1) {
            cin >> k;
            modify (1, x, y, k);
        }
        else {
            cout << query (1, x, y) << endl;
        }
    }
}
posted @ 2022-03-28 20:52  Sakana~  阅读(36)  评论(3编辑  收藏  举报