[模板] 线段树

同 Luogu P3373

注意如果写 pushup 的话不要越界
注意更新 sum 值的位置

# include <iostream>
# include <cstdio>
# define MAXN 100000+5
# define LL long long

using namespace std;

struct node{
    int l, r;
    int lazyA;
    LL sum;
}a[MAXN<<2];

int lim;

void pushdown(int now){
    if(a[now].lazyA){
        a[now<<1].sum += (a[now<<1].r - a[now<<1].l + 1) * a[now].lazyA;
        a[now<<1|1].sum += (a[now<<1|1].r - a[now<<1|1].l + 1) * a[now].lazyA;
        a[now<<1].lazyA += a[now].lazyA, a[now<<1|1].lazyA += a[now].lazyA;
        a[now].lazyA = 0; 
    }
    return;
}

void build(int now, int l, int r){
    a[now].l = l, a[now].r = r;

    if(l == r){
        scanf("%lld", &a[now].sum);
        return;
    }

    int mid = ( l + r ) >> 1;
    build(now<<1, l, mid);
    build(now<<1|1, mid+1, r);
    a[now].sum = a[now<<1].sum + a[now<<1|1].sum;
    return;
}

void add(int now, int l, int r, LL val){
    if(a[now].l >= l && a[now].r <= r){
        a[now].sum += val * (a[now].r - a[now].l + 1);
        a[now].lazyA  += val; // 当前节点的区间被完全覆盖的情况
        return;
    }
    pushdown(now);

    int mid = (a[now].l + a[now].r) >> 1;
    if(l <= mid) add(now<<1, l, r, val);
    if(r > mid) add(now<<1|1, l, r, val);
    // 因为上面的限定是完全覆盖所以 l r 打法不会出问题
    a[now].sum = a[now<<1].sum + a[now<<1|1].sum;
    return;
}

LL ask(int now, int l, int r){
    if(a[now].l >= l && a[now].r <= r)
        return a[now].sum;
    pushdown(now);
    
    LL sum = 0;
    int mid = (a[now].l + a[now].r) >> 1;
    if(l <= mid) sum += ask(now<<1, l, r);
    if(r > mid) sum += ask(now<<1|1, l, r);
    return sum;
}

int main(){
    int n, m, opt, x, y, k;
    scanf("%d%d", &n, &m);
    build(1, 1, n);
    for(int i = 1; i <= m; i++){
        scanf("%d", &opt);
        if(opt == 1){
            scanf("%d%d%d", &x, &y, &k);
            add(1, x, y, k);
        }
        else{
            scanf("%d%d", &x, &y);
            printf("%lld\n", ask(1, x, y));
        }
    }
    return 0;
}
posted @ 2020-06-05 19:06  ChPu437  阅读(131)  评论(0编辑  收藏  举报